slotlock 0.2.0 → 0.5.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 (66) hide show
  1. package/CHANGELOG.md +582 -0
  2. package/CONTRIBUTING.md +35 -8
  3. package/GOVERNANCE.md +4 -2
  4. package/MAINTAINERS.md +3 -2
  5. package/NOTICE +4 -4
  6. package/README.md +498 -65
  7. package/SECURITY.md +31 -2
  8. package/SPEC.md +142 -15
  9. package/agent-server.d.ts +62 -10
  10. package/agent-server.js +577 -105
  11. package/agent-store-backend.d.ts +12 -0
  12. package/agent-store-backend.js +1115 -55
  13. package/api-keys.d.ts +11 -3
  14. package/api-keys.js +29 -6
  15. package/application-api.d.ts +35 -1
  16. package/application-api.js +683 -12
  17. package/booking-rules.d.ts +84 -0
  18. package/booking-rules.js +149 -0
  19. package/config.d.ts +112 -0
  20. package/config.js +225 -0
  21. package/dashboard.d.ts +67 -5
  22. package/dashboard.js +1012 -140
  23. package/ddl.d.ts +45 -3
  24. package/ddl.js +1124 -13
  25. package/engine.d.ts +5 -0
  26. package/engine.js +23 -6
  27. package/event-feed.d.ts +178 -0
  28. package/event-feed.js +435 -0
  29. package/event-schema.d.ts +59 -0
  30. package/event-schema.js +85 -0
  31. package/ical-worker-thread.js +4 -2
  32. package/ical-worker.d.ts +8 -5
  33. package/ical-worker.js +9 -2
  34. package/index.d.ts +12 -6
  35. package/index.js +9 -4
  36. package/interop.d.ts +117 -0
  37. package/interop.js +356 -0
  38. package/maintenance.d.ts +27 -5
  39. package/maintenance.js +92 -28
  40. package/mcp-app.d.ts +7 -1
  41. package/mcp-app.js +259 -40
  42. package/metrics.d.ts +24 -0
  43. package/metrics.js +167 -0
  44. package/node-server.d.ts +9 -1
  45. package/node-server.js +7 -2
  46. package/openapi.json +10970 -0
  47. package/package.json +3 -2
  48. package/rate-limit.d.ts +80 -0
  49. package/rate-limit.js +741 -0
  50. package/rest-api.d.ts +22 -0
  51. package/rest-api.js +166 -11
  52. package/rules.js +6 -3
  53. package/self-host.d.ts +45 -8
  54. package/self-host.js +616 -46
  55. package/slotlock-manifest.schema.json +7 -1
  56. package/slotlock.manifest.json +8 -2
  57. package/store.d.ts +647 -28
  58. package/store.js +2982 -327
  59. package/sync.d.ts +43 -2
  60. package/sync.js +1515 -323
  61. package/timezone.d.ts +58 -3
  62. package/timezone.js +249 -20
  63. package/types.d.ts +300 -9
  64. package/types.js +0 -2
  65. package/webhooks.d.ts +91 -0
  66. package/webhooks.js +300 -0
@@ -0,0 +1,59 @@
1
+ import { z } from 'zod';
2
+ export declare const SLOTLOCK_EVENT_OUTPUT: z.ZodObject<{
3
+ id: z.ZodString;
4
+ resource_id: z.ZodString;
5
+ starts_at: z.ZodString;
6
+ ends_at: z.ZodString;
7
+ timezone: z.ZodString;
8
+ title: z.ZodNullable<z.ZodString>;
9
+ description: z.ZodNullable<z.ZodString>;
10
+ location: z.ZodNullable<z.ZodString>;
11
+ organizer: z.ZodNullable<z.ZodObject<{
12
+ address: z.ZodString;
13
+ name: z.ZodNullable<z.ZodString>;
14
+ }, z.core.$strict>>;
15
+ attendees: z.ZodArray<z.ZodObject<{
16
+ address: z.ZodString;
17
+ name: z.ZodNullable<z.ZodString>;
18
+ role: z.ZodEnum<{
19
+ chair: "chair";
20
+ non_participant: "non_participant";
21
+ optional: "optional";
22
+ required: "required";
23
+ }>;
24
+ participation_status: z.ZodEnum<{
25
+ accepted: "accepted";
26
+ declined: "declined";
27
+ delegated: "delegated";
28
+ needs_action: "needs_action";
29
+ tentative: "tentative";
30
+ }>;
31
+ rsvp: z.ZodBoolean;
32
+ }, z.core.$strict>>;
33
+ reminders: z.ZodArray<z.ZodObject<{
34
+ minutes_before: z.ZodNumber;
35
+ channel: z.ZodEnum<{
36
+ display: "display";
37
+ email: "email";
38
+ }>;
39
+ }, z.core.$strict>>;
40
+ status: z.ZodEnum<{
41
+ cancelled: "cancelled";
42
+ confirmed: "confirmed";
43
+ tentative: "tentative";
44
+ }>;
45
+ transparency: z.ZodEnum<{
46
+ opaque: "opaque";
47
+ transparent: "transparent";
48
+ }>;
49
+ sequence: z.ZodNumber;
50
+ revision: z.ZodNumber;
51
+ recurrence_rule: z.ZodNullable<z.ZodString>;
52
+ recurrence_exceptions: z.ZodArray<z.ZodObject<{
53
+ recurrence_id: z.ZodString;
54
+ cancelled: z.ZodBoolean;
55
+ starts_at: z.ZodNullable<z.ZodString>;
56
+ ends_at: z.ZodNullable<z.ZodString>;
57
+ }, z.core.$strict>>;
58
+ recurrence_id: z.ZodNullable<z.ZodString>;
59
+ }, z.core.$strict>;
@@ -0,0 +1,85 @@
1
+ // A calendar event as the event tools return it, and as the application API returns any of a
2
+ // tenant's events. Its own module because both the agent server and the application API describe
3
+ // events with it, and the application API imports nothing from the agent server at runtime (the
4
+ // agent server imports it, so the reverse would be a cycle).
5
+ import { z } from 'zod';
6
+ const DATE_TIME = z.string().datetime({ offset: true });
7
+ const RESOURCE_ID = z.string().trim().min(1).max(200);
8
+ const EVENT_ID = z.string().trim().min(1).max(500);
9
+ const REVISION = z.number().int().positive();
10
+ // Output bounds mirror the trusted store's byte ceilings. A value admitted by a UTF-8 byte
11
+ // ceiling can never exceed that many UTF-16 code units, so every valid stored/provider event is
12
+ // serializable without truncating recurrence semantics or calendar identities.
13
+ const TRUSTED_SUMMARY_OUTPUT_MAX = 4_096;
14
+ const TRUSTED_TEXT_OUTPUT_MAX = 16_384;
15
+ const TRUSTED_PERSON_NAME_OUTPUT_MAX = 1_024;
16
+ const TRUSTED_RECURRENCE_EXCEPTION_OUTPUT_MAX = 1_000;
17
+ const TRUSTED_REMINDER_MINUTES_OUTPUT_MAX = 366 * 24 * 60;
18
+ // The grammar the store keeps an address in (normalizeEmail in sync.ts), so every stored one can be
19
+ // returned: an address from an imported feed need not be one z.email() takes (ops@localhost).
20
+ const STORED_ADDRESS = z
21
+ .string()
22
+ .min(3)
23
+ .max(320)
24
+ .refine((value) => /^[^\s@]+@[^\s@]+$/.test(value), {
25
+ message: 'must be one @ between characters other than spaces',
26
+ });
27
+ const ORGANIZER = z
28
+ .object({
29
+ address: STORED_ADDRESS,
30
+ name: z.string().trim().max(TRUSTED_PERSON_NAME_OUTPUT_MAX).nullable(),
31
+ })
32
+ .strict();
33
+ const ATTENDEE = z
34
+ .object({
35
+ address: STORED_ADDRESS,
36
+ name: z.string().trim().max(TRUSTED_PERSON_NAME_OUTPUT_MAX).nullable(),
37
+ role: z.enum(['chair', 'required', 'optional', 'non_participant']),
38
+ participation_status: z.enum([
39
+ 'needs_action',
40
+ 'accepted',
41
+ 'declined',
42
+ 'tentative',
43
+ 'delegated',
44
+ ]),
45
+ rsvp: z.boolean(),
46
+ })
47
+ .strict();
48
+ const REMINDER = z
49
+ .object({
50
+ minutes_before: z.number().int().min(0).max(TRUSTED_REMINDER_MINUTES_OUTPUT_MAX),
51
+ channel: z.enum(['display', 'email']),
52
+ })
53
+ .strict();
54
+ const RECURRENCE_EXCEPTION = z
55
+ .object({
56
+ recurrence_id: DATE_TIME,
57
+ cancelled: z.boolean(),
58
+ starts_at: DATE_TIME.nullable(),
59
+ ends_at: DATE_TIME.nullable(),
60
+ })
61
+ .strict();
62
+ export const SLOTLOCK_EVENT_OUTPUT = z
63
+ .object({
64
+ id: EVENT_ID,
65
+ resource_id: RESOURCE_ID,
66
+ starts_at: DATE_TIME,
67
+ ends_at: DATE_TIME,
68
+ timezone: z.string().min(1).max(100),
69
+ title: z.string().max(TRUSTED_SUMMARY_OUTPUT_MAX).nullable(),
70
+ description: z.string().max(TRUSTED_TEXT_OUTPUT_MAX).nullable(),
71
+ location: z.string().max(TRUSTED_TEXT_OUTPUT_MAX).nullable(),
72
+ organizer: ORGANIZER.nullable(),
73
+ attendees: z.array(ATTENDEE).max(100),
74
+ reminders: z.array(REMINDER).max(20),
75
+ status: z.enum(['tentative', 'confirmed', 'cancelled']),
76
+ transparency: z.enum(['opaque', 'transparent']),
77
+ sequence: z.number().int().nonnegative(),
78
+ revision: REVISION,
79
+ recurrence_rule: z.string().max(TRUSTED_SUMMARY_OUTPUT_MAX).nullable(),
80
+ recurrence_exceptions: z
81
+ .array(RECURRENCE_EXCEPTION)
82
+ .max(TRUSTED_RECURRENCE_EXCEPTION_OUTPUT_MAX),
83
+ recurrence_id: DATE_TIME.nullable(),
84
+ })
85
+ .strict();
@@ -1,7 +1,7 @@
1
1
  // One worker of createICalendarWorkerPool: reads the feeds it is sent with the ordinary parsers and
2
2
  // posts back what they return, or the code of the CalendarContractError they throw.
3
3
  import { parentPort } from 'node:worker_threads';
4
- import { CalendarContractError, CalendarExpansionLimitError, parseICalendarChanges, parseTrustedICalendarEvents, } from './sync.js';
4
+ import { CalendarContractError, CalendarExpansionLimitError, parseICalendarChanges, parseICalendarFeed, parseTrustedICalendarEvents, } from './sync.js';
5
5
  const port = parentPort;
6
6
  if (!port)
7
7
  throw new Error('slotlock: ical-worker-thread runs only as a worker thread');
@@ -10,7 +10,9 @@ port.on('message', (request) => {
10
10
  try {
11
11
  const value = request.op === 'changes'
12
12
  ? parseICalendarChanges(request.input, request.calendarTimezone, request.window)
13
- : parseTrustedICalendarEvents(request.input, request.calendarTimezone);
13
+ : request.op === 'feed'
14
+ ? parseICalendarFeed(request.input, request.calendarTimezone, request.window)
15
+ : parseTrustedICalendarEvents(request.input, request.calendarTimezone);
14
16
  reply = { id: request.id, ok: true, value };
15
17
  }
16
18
  catch (error) {
package/ical-worker.d.ts CHANGED
@@ -1,9 +1,9 @@
1
- import { CalendarContractError, type ExternalCalendarChange, type ICalendarExpansionWindow } from './sync.js';
1
+ import { CalendarContractError, type ExternalCalendarChange, type ICalendarExpansionWindow, type ICalendarFeedRead } from './sync.js';
2
2
  import type { TrustedICalendarEvent } from './types.js';
3
3
  /** What the pool posts to a worker. */
4
4
  export type ICalendarWorkerRequest = {
5
5
  id: number;
6
- op: 'changes';
6
+ op: 'changes' | 'feed';
7
7
  input: string;
8
8
  calendarTimezone: string | undefined;
9
9
  window: ICalendarExpansionWindow | undefined;
@@ -29,8 +29,8 @@ export interface ICalendarWorkerPoolOptions {
29
29
  size?: number;
30
30
  /**
31
31
  * How long one parse may run on its worker, in ms, before the worker is stopped and the feed
32
- * refused (CalendarExpansionLimitError), 100-60,000. Defaults to 3,000: three times the parser's
33
- * own limit, with room for a new worker to start.
32
+ * refused (CalendarExpansionLimitError), 100-60,000. Defaults to 3,000: several times what the
33
+ * parser's step budget takes, with room for a new worker to start.
34
34
  */
35
35
  deadlineMs?: number;
36
36
  /** Parses that may wait for a worker, 0-10,000; more are refused at once. Defaults to 64. */
@@ -46,6 +46,8 @@ export interface ICalendarWorkerPoolOptions {
46
46
  export interface ICalendarWorkerPool {
47
47
  /** `parseICalendarChanges`, run on a worker. */
48
48
  parseICalendarChanges(input: string, calendarTimezone?: string, expansionWindow?: ICalendarExpansionWindow): Promise<ExternalCalendarChange[]>;
49
+ /** `parseICalendarFeed`, run on a worker. */
50
+ parseICalendarFeed(input: string, calendarTimezone?: string, expansionWindow?: ICalendarExpansionWindow): Promise<ICalendarFeedRead>;
49
51
  /** `parseTrustedICalendarEvents`, run on a worker. */
50
52
  parseTrustedICalendarEvents(input: string, calendarTimezone?: string): Promise<TrustedICalendarEvent[]>;
51
53
  /** Refuse waiting parses and stop every worker. */
@@ -63,7 +65,8 @@ export declare class ICalendarWorkerPoolClosedError extends Error {
63
65
  }
64
66
  /**
65
67
  * A pool of worker threads that read untrusted iCalendar for the calling thread. Results and
66
- * errors are those of `parseICalendarChanges` and `parseTrustedICalendarEvents` (the same
68
+ * errors are those of `parseICalendarChanges`, `parseICalendarFeed` and
69
+ * `parseTrustedICalendarEvents` (the same
67
70
  * `CalendarContractError` codes), plus CalendarExpansionLimitError when a worker passes its
68
71
  * deadline or its heap, ICalendarWorkerBusyError when the queue is full, and
69
72
  * ICalendarWorkerPoolClosedError after `close()`. Idle workers do not keep the process alive.
package/ical-worker.js CHANGED
@@ -31,7 +31,8 @@ function workerFailure(error) {
31
31
  }
32
32
  /**
33
33
  * A pool of worker threads that read untrusted iCalendar for the calling thread. Results and
34
- * errors are those of `parseICalendarChanges` and `parseTrustedICalendarEvents` (the same
34
+ * errors are those of `parseICalendarChanges`, `parseICalendarFeed` and
35
+ * `parseTrustedICalendarEvents` (the same
35
36
  * `CalendarContractError` codes), plus CalendarExpansionLimitError when a worker passes its
36
37
  * deadline or its heap, ICalendarWorkerBusyError when the queue is full, and
37
38
  * ICalendarWorkerPoolClosedError after `close()`. Idle workers do not keep the process alive.
@@ -134,7 +135,7 @@ export function createICalendarWorkerPool(options = {}) {
134
135
  if (request.calendarTimezone !== undefined && typeof request.calendarTimezone !== 'string') {
135
136
  throw new CalendarContractError('invalid_icalendar');
136
137
  }
137
- if (request.op === 'changes' &&
138
+ if (request.op !== 'trusted' &&
138
139
  request.window !== undefined &&
139
140
  !(request.window?.start instanceof Date && request.window.end instanceof Date)) {
140
141
  throw new CalendarContractError('invalid_icalendar');
@@ -172,6 +173,12 @@ export function createICalendarWorkerPool(options = {}) {
172
173
  window,
173
174
  }));
174
175
  },
176
+ async parseICalendarFeed(input, calendarTimezone, expansionWindow) {
177
+ const window = expansionWindow
178
+ ? { start: expansionWindow.start, end: expansionWindow.end }
179
+ : undefined;
180
+ return (await run({ op: 'feed', input, calendarTimezone, window }));
181
+ },
175
182
  async parseTrustedICalendarEvents(input, calendarTimezone) {
176
183
  return (await run({ op: 'trusted', input, calendarTimezone }));
177
184
  },
package/index.d.ts CHANGED
@@ -1,8 +1,14 @@
1
1
  /// <reference types="node" preserve="true" />
2
2
  export { findNextAvailable, mergeIntervals, subtractBusy } from './engine.js';
3
+ export { type SlotlockBookingRule, type SlotlockBookingRules, bookingRuleBroken, bookingSearch, nextStepStart, parseBookingRules, } from './booking-rules.js';
4
+ export { type CreateWebhookEndpointResult, type ListChangesResult, SLOTLOCK_CHANGE_RETENTION_DAYS, SLOTLOCK_CHANGE_TYPES, SLOTLOCK_MAX_WEBHOOK_ENDPOINTS, SLOTLOCK_WEBHOOK_FAILING_LIMIT_MS, type SlotlockChange, type SlotlockChangeType, type SlotlockEventFeed, type SlotlockWebhookClaim, type SlotlockWebhookEndpoint, } from './event-feed.js';
5
+ export { type SlotlockCloudEvent, type SlotlockWebhookPassResult, type SlotlockWebhookResponse, type SlotlockWebhookScheduler, type SlotlockWebhookSender, createSlotlockWebhookSender, deliverSlotlockWebhooks, isPrivateAddress, signSlotlockWebhook, slotlockCloudEvent, slotlockWebhookRetryDelayMs, startSlotlockWebhookDelivery, } from './webhooks.js';
6
+ export { type SlotlockMetrics, createSlotlockMetrics } from './metrics.js';
3
7
  export { expandRules } from './rules.js';
4
8
  export { availabilityRuleProblem, parseAvailabilityRules, rulesToWeeklyHours, SLOTLOCK_MAX_AVAILABILITY_RULES, weeklyHoursToRules, } from './weekly-hours.js';
5
9
  export type { HoursWindow, Weekday, WeeklyHours } from './weekly-hours.js';
10
+ export { emitVAvailability, parseVAvailability, recurrenceRuleFromRRule, SLOTLOCK_MAX_VAVAILABILITY_CHARACTERS, toJSCalendarEvent, } from './interop.js';
11
+ export type { EmitVAvailabilityOptions, JSCalendarAlert, JSCalendarEvent, JSCalendarParticipant, JSCalendarRecurrenceRule, ParsedVAvailability, } from './interop.js';
6
12
  export { createTimeZoneConverter, zonedCalendarDate, zonedDateTimeToUtc, zonedWallTime, } from './timezone.js';
7
13
  export type { LocalDateTime, TimeZoneConverter, ZonedCalendarDate, ZonedWallTime, } from './timezone.js';
8
14
  export { createSlotlockAgentServer, clientSupportsSlotlockMcpApp, invokeSlotlockAgentOperation, isSlotlockAgentOperation, slotlockAgentTools, slotlockApplicationOperations, slotlockOpenApi, slotlockCalendarResourceUri, slotlockMcpToolResult, parseSlotlockA2ATimestamp, resolveSlotlockAgentOperation, slotlockAgentOperationScope, SLOTLOCK_A2A_PROTOCOL_VERSION, SLOTLOCK_A2A_TASK_PAGE_SIZE, SLOTLOCK_A2A_TASK_STATES, SLOTLOCK_AGENT_OPERATION_LEGACY_NAMES, SLOTLOCK_AGENT_SERVER_VERSION, SLOTLOCK_MCP_LEGACY_PROTOCOL_VERSION, SLOTLOCK_MCP_PROTOCOL_VERSION, SLOTLOCK_MCP_RATE_LIMITED_ERROR_CODE, SLOTLOCK_MCP_RESOURCE_URI_TEMPLATE, SLOTLOCK_MCP_SUPPORTED_PROTOCOL_VERSIONS, SLOTLOCK_MCP_APP_HTML, SLOTLOCK_MCP_APP_MIME_TYPE, SLOTLOCK_MCP_APP_RESOURCE, SLOTLOCK_MCP_APP_RESOURCE_URI, SLOTLOCK_MCP_APPS_EXTENSION, SlotlockAgentOperationError, } from './agent-server.js';
@@ -16,13 +22,13 @@ export type { SlotlockApplicationBackend, SlotlockApplicationInvocationContext,
16
22
  export { maintainSlotlockTenant, startSlotlockMaintenance, withSlotlockMaintenanceLock, } from './maintenance.js';
17
23
  export type { SlotlockMaintenanceResult, SlotlockMaintenanceScheduler, SlotlockMaintenanceSchedulerOptions, } from './maintenance.js';
18
24
  export { createSlotlockApiKeyAuthenticator, createSlotlockApiKeyStore, generateSlotlockApiKey, isSlotlockApiKey, slotlockApiKeyDigest, SLOTLOCK_API_KEY_ACTIVE_LIMIT, SLOTLOCK_API_KEY_MAX_LIFETIME_DAYS, SLOTLOCK_API_KEY_PREFIX, SLOTLOCK_API_KEY_RETAINED_LIMIT, SLOTLOCK_API_KEY_SCOPES, } from './api-keys.js';
19
- export { createSlotlockDashboard, createSlotlockDashboardResources, createSlotlockDashboardState, createSlotlockMemoryDashboardState, SLOTLOCK_DASHBOARD_MAX_RESOURCES, } from './dashboard.js';
25
+ export { createSlotlockDashboard, createSlotlockDashboardResources, createSlotlockAcceptanceRecords, createSlotlockDashboardState, createSlotlockMemoryDashboardState, SLOTLOCK_DASHBOARD_MAX_RESOURCES, } from './dashboard.js';
20
26
  export type { SlotlockDashboard, SlotlockDashboardOptions, SlotlockDashboardResources, SlotlockDashboardState, } from './dashboard.js';
21
27
  export type { CreateSlotlockApiKeyInput, SlotlockApiKey, SlotlockApiKeyAuthenticatorOptions, SlotlockApiKeyIdentity, SlotlockApiKeyScope, SlotlockApiKeyStore, } from './api-keys.js';
22
28
  export { ICalendarWorkerBusyError, ICalendarWorkerPoolClosedError, createICalendarWorkerPool, } from './ical-worker.js';
23
29
  export type { ICalendarWorkerPool, ICalendarWorkerPoolOptions } from './ical-worker.js';
24
- export { CalendarContractError, CalendarExpansionLimitError, emitICalendar, emitITipCalendar, expandCalendarEventOccurrences, normalizeCalendarEventContent, normalizeExternalCalendarChange, parseICalendarChanges, parseTrustedICalendarEvents, } from './sync.js';
25
- export type { ExternalCalendarChange, ExternalCalendarChangeInput, ExternalCalendarStatus, ICalendarEvent, ICalendarExpansionWindow, ITipMethod, } from './sync.js';
26
- export { createSlotlockApplicationRoleGrantsDdl, createSlotlockTenantRlsDdl, SLOTLOCK_API_KEY_FUNCTIONS, SLOTLOCK_API_KEY_TABLES, SLOTLOCK_CORE_DDL, SLOTLOCK_DASHBOARD_FUNCTIONS, SLOTLOCK_DASHBOARD_TABLES, SLOTLOCK_DEFINER_FUNCTIONS, SLOTLOCK_DEFINER_TABLES, SLOTLOCK_TENANT_CONTEXT_SETTING, SLOTLOCK_TENANT_RLS_DDL, SLOTLOCK_TENANT_TABLES, } from './ddl.js';
27
- export { calendarEventRollingHorizon, createSlotlockStore, SLOTLOCK_AGENT_OWNER_COMMAND_QUOTA, SLOTLOCK_AGENT_OWNER_EVENT_QUOTA, SLOTLOCK_CALENDAR_HORIZON_DAYS, SLOTLOCK_EVENT_COMMAND_RETENTION_DAYS, SLOTLOCK_INTERNAL_EVENT_OWNER_REF, SLOTLOCK_LOCAL_RECURRENCE_COVERAGE_SOURCE, SLOTLOCK_MAX_EVENT_DURATION_DAYS, type SlotlockHoldTenantOptions, type SlotlockSql, type SlotlockStore, type SlotlockStoreOptions, type SlotlockTenantStore, } from './store.js';
28
- export type { AcquireHoldResult, CalendarAttendee, CalendarAttendeeRole, CalendarCoverageAssessment, CalendarCoverageCommand, CalendarCoverageResult, CalendarEventContent, CalendarEventOccurrence, CalendarEventRetentionResult, CalendarEventStatus, CalendarFreeBusy, CalendarHorizonRollCursor, CalendarHorizonRollResult, CalendarOrganizer, CalendarParticipationStatus, CalendarRecurrence, CalendarRecurrenceException, CalendarReminder, CalendarTransparency, ConfirmHoldResult, CancelCalendarEventResult, CancelExternalReservationResult, CreateReservationResult, ExternalReservationCommand, ExternalReservationResult, Interval, SlotlockHold, SlotlockCalendarEvent, SlotlockReservation, SlotlockResource, PutCalendarEventCommand, PutCalendarEventResult, ReleaseHoldResult, TrustedICalendarEvent, WeeklyAvailabilityRule, } from './types.js';
30
+ export { CalendarContractError, CalendarExpansionLimitError, emitICalendar, emitITipCalendar, expandCalendarEventOccurrences, normalizeCalendarEventContent, normalizeExternalCalendarChange, parseICalendarChanges, parseICalendarFeed, parseTrustedICalendarEvents, recurrenceRuleProblem, storedCalendarEventProblem, } from './sync.js';
31
+ export type { ExternalCalendarChange, ExternalCalendarChangeInput, ExternalCalendarStatus, ICalendarEvent, ICalendarExpansionWindow, ICalendarFeedRead, ICalendarSeriesRefusal, ITipMethod, } from './sync.js';
32
+ export { createSlotlockApplicationRoleGrantsDdl, createSlotlockTenantRlsDdl, SLOTLOCK_API_KEY_FUNCTIONS, SLOTLOCK_API_KEY_TABLES, SLOTLOCK_CORE_DDL, SLOTLOCK_DASHBOARD_FUNCTIONS, SLOTLOCK_DASHBOARD_TABLES, SLOTLOCK_DEFINER_FUNCTIONS, SLOTLOCK_DEFINER_TABLES, SLOTLOCK_OPERATOR_FUNCTIONS, SLOTLOCK_SCHEMA_FUNCTIONS, SLOTLOCK_SCHEMA_TABLES, SLOTLOCK_SCHEMA_VERSION, SLOTLOCK_TENANT_ADMIN_FUNCTIONS, SLOTLOCK_TENANT_ADMIN_TABLES, SLOTLOCK_TENANT_CONTEXT_SETTING, SLOTLOCK_TENANT_RLS_DDL, SLOTLOCK_TENANT_TABLES, } from './ddl.js';
33
+ export { assertSlotlockSchemaCurrent, calendarEventRollingHorizon, createSlotlockStore, readSlotlockSchemaVersion, SLOTLOCK_AGENT_OWNER_COMMAND_QUOTA, SLOTLOCK_AGENT_OWNER_EVENT_QUOTA, SLOTLOCK_CALENDAR_HORIZON_DAYS, SLOTLOCK_EVENT_COMMAND_RETENTION_DAYS, SLOTLOCK_INTERNAL_EVENT_OWNER_REF, SLOTLOCK_LOCAL_RECURRENCE_COVERAGE_SOURCE, SLOTLOCK_MATERIALIZATION_WINDOW_DAYS, SLOTLOCK_MAX_EVENT_DURATION_DAYS, SLOTLOCK_TENANT_WRITE_METHODS, type SlotlockHoldTenantOptions, type SlotlockMigrationOptions, type SlotlockSql, type SlotlockStore, type SlotlockStoreOptions, type SlotlockTenantLimits, type SlotlockTenantStore, } from './store.js';
34
+ export type { AcquireHoldResult, BookingRetentionResult, CalendarAttendee, CalendarAttendeeRole, CalendarCoverageAssessment, CalendarCoverageCommand, CalendarCoverageResult, CalendarEventContent, CalendarEventOccurrence, CalendarEventRetentionResult, CalendarEventStatus, CalendarFreeBusy, CalendarHorizonRollCursor, CalendarHorizonRollResult, CalendarOrganizer, CalendarParticipationStatus, CalendarRecurrence, CalendarRecurrenceException, CalendarReminder, CalendarTransparency, ConfirmHoldResult, CancelCalendarEventResult, CancelExternalReservationResult, CreateReservationResult, DeleteResourceResult, ExternalReservationCommand, ExternalReservationResult, Interval, SlotlockAgendaEntry, SlotlockHold, SlotlockCalendarEvent, SlotlockReservation, SlotlockResource, SlotlockTenantErasure, PutCalendarEventCommand, PutCalendarEventResult, ReleaseHoldResult, TrustedICalendarEvent, WeeklyAvailabilityRule, } from './types.js';
package/index.js CHANGED
@@ -4,8 +4,13 @@
4
4
  // TypeScript 6 default) still loads @types/node.
5
5
  /// <reference types="node" preserve="true" />
6
6
  export { findNextAvailable, mergeIntervals, subtractBusy } from './engine.js';
7
+ export { bookingRuleBroken, bookingSearch, nextStepStart, parseBookingRules, } from './booking-rules.js';
8
+ export { SLOTLOCK_CHANGE_RETENTION_DAYS, SLOTLOCK_CHANGE_TYPES, SLOTLOCK_MAX_WEBHOOK_ENDPOINTS, SLOTLOCK_WEBHOOK_FAILING_LIMIT_MS, } from './event-feed.js';
9
+ export { createSlotlockWebhookSender, deliverSlotlockWebhooks, isPrivateAddress, signSlotlockWebhook, slotlockCloudEvent, slotlockWebhookRetryDelayMs, startSlotlockWebhookDelivery, } from './webhooks.js';
10
+ export { createSlotlockMetrics } from './metrics.js';
7
11
  export { expandRules } from './rules.js';
8
12
  export { availabilityRuleProblem, parseAvailabilityRules, rulesToWeeklyHours, SLOTLOCK_MAX_AVAILABILITY_RULES, weeklyHoursToRules, } from './weekly-hours.js';
13
+ export { emitVAvailability, parseVAvailability, recurrenceRuleFromRRule, SLOTLOCK_MAX_VAVAILABILITY_CHARACTERS, toJSCalendarEvent, } from './interop.js';
9
14
  export { createTimeZoneConverter, zonedCalendarDate, zonedDateTimeToUtc, zonedWallTime, } from './timezone.js';
10
15
  export { createSlotlockAgentServer, clientSupportsSlotlockMcpApp, invokeSlotlockAgentOperation, isSlotlockAgentOperation, slotlockAgentTools, slotlockApplicationOperations, slotlockOpenApi, slotlockCalendarResourceUri, slotlockMcpToolResult, parseSlotlockA2ATimestamp, resolveSlotlockAgentOperation, slotlockAgentOperationScope, SLOTLOCK_A2A_PROTOCOL_VERSION, SLOTLOCK_A2A_TASK_PAGE_SIZE, SLOTLOCK_A2A_TASK_STATES, SLOTLOCK_AGENT_OPERATION_LEGACY_NAMES, SLOTLOCK_AGENT_SERVER_VERSION, SLOTLOCK_MCP_LEGACY_PROTOCOL_VERSION, SLOTLOCK_MCP_PROTOCOL_VERSION, SLOTLOCK_MCP_RATE_LIMITED_ERROR_CODE, SLOTLOCK_MCP_RESOURCE_URI_TEMPLATE, SLOTLOCK_MCP_SUPPORTED_PROTOCOL_VERSIONS, SLOTLOCK_MCP_APP_HTML, SLOTLOCK_MCP_APP_MIME_TYPE, SLOTLOCK_MCP_APP_RESOURCE, SLOTLOCK_MCP_APP_RESOURCE_URI, SLOTLOCK_MCP_APPS_EXTENSION, SlotlockAgentOperationError, } from './agent-server.js';
11
16
  export { createSlotlockNodeServer } from './node-server.js';
@@ -13,8 +18,8 @@ export { createSlotlockStoreAgentBackend, createSlotlockStoreApplicationBackend,
13
18
  export { SLOTLOCK_APPLICATION_OPERATIONS, SLOTLOCK_APPLICATION_SCOPE, isSlotlockApplicationOperation, } from './application-api.js';
14
19
  export { maintainSlotlockTenant, startSlotlockMaintenance, withSlotlockMaintenanceLock, } from './maintenance.js';
15
20
  export { createSlotlockApiKeyAuthenticator, createSlotlockApiKeyStore, generateSlotlockApiKey, isSlotlockApiKey, slotlockApiKeyDigest, SLOTLOCK_API_KEY_ACTIVE_LIMIT, SLOTLOCK_API_KEY_MAX_LIFETIME_DAYS, SLOTLOCK_API_KEY_PREFIX, SLOTLOCK_API_KEY_RETAINED_LIMIT, SLOTLOCK_API_KEY_SCOPES, } from './api-keys.js';
16
- export { createSlotlockDashboard, createSlotlockDashboardResources, createSlotlockDashboardState, createSlotlockMemoryDashboardState, SLOTLOCK_DASHBOARD_MAX_RESOURCES, } from './dashboard.js';
21
+ export { createSlotlockDashboard, createSlotlockDashboardResources, createSlotlockAcceptanceRecords, createSlotlockDashboardState, createSlotlockMemoryDashboardState, SLOTLOCK_DASHBOARD_MAX_RESOURCES, } from './dashboard.js';
17
22
  export { ICalendarWorkerBusyError, ICalendarWorkerPoolClosedError, createICalendarWorkerPool, } from './ical-worker.js';
18
- export { CalendarContractError, CalendarExpansionLimitError, emitICalendar, emitITipCalendar, expandCalendarEventOccurrences, normalizeCalendarEventContent, normalizeExternalCalendarChange, parseICalendarChanges, parseTrustedICalendarEvents, } from './sync.js';
19
- export { createSlotlockApplicationRoleGrantsDdl, createSlotlockTenantRlsDdl, SLOTLOCK_API_KEY_FUNCTIONS, SLOTLOCK_API_KEY_TABLES, SLOTLOCK_CORE_DDL, SLOTLOCK_DASHBOARD_FUNCTIONS, SLOTLOCK_DASHBOARD_TABLES, SLOTLOCK_DEFINER_FUNCTIONS, SLOTLOCK_DEFINER_TABLES, SLOTLOCK_TENANT_CONTEXT_SETTING, SLOTLOCK_TENANT_RLS_DDL, SLOTLOCK_TENANT_TABLES, } from './ddl.js';
20
- export { calendarEventRollingHorizon, createSlotlockStore, SLOTLOCK_AGENT_OWNER_COMMAND_QUOTA, SLOTLOCK_AGENT_OWNER_EVENT_QUOTA, SLOTLOCK_CALENDAR_HORIZON_DAYS, SLOTLOCK_EVENT_COMMAND_RETENTION_DAYS, SLOTLOCK_INTERNAL_EVENT_OWNER_REF, SLOTLOCK_LOCAL_RECURRENCE_COVERAGE_SOURCE, SLOTLOCK_MAX_EVENT_DURATION_DAYS, } from './store.js';
23
+ export { CalendarContractError, CalendarExpansionLimitError, emitICalendar, emitITipCalendar, expandCalendarEventOccurrences, normalizeCalendarEventContent, normalizeExternalCalendarChange, parseICalendarChanges, parseICalendarFeed, parseTrustedICalendarEvents, recurrenceRuleProblem, storedCalendarEventProblem, } from './sync.js';
24
+ export { createSlotlockApplicationRoleGrantsDdl, createSlotlockTenantRlsDdl, SLOTLOCK_API_KEY_FUNCTIONS, SLOTLOCK_API_KEY_TABLES, SLOTLOCK_CORE_DDL, SLOTLOCK_DASHBOARD_FUNCTIONS, SLOTLOCK_DASHBOARD_TABLES, SLOTLOCK_DEFINER_FUNCTIONS, SLOTLOCK_DEFINER_TABLES, SLOTLOCK_OPERATOR_FUNCTIONS, SLOTLOCK_SCHEMA_FUNCTIONS, SLOTLOCK_SCHEMA_TABLES, SLOTLOCK_SCHEMA_VERSION, SLOTLOCK_TENANT_ADMIN_FUNCTIONS, SLOTLOCK_TENANT_ADMIN_TABLES, SLOTLOCK_TENANT_CONTEXT_SETTING, SLOTLOCK_TENANT_RLS_DDL, SLOTLOCK_TENANT_TABLES, } from './ddl.js';
25
+ export { assertSlotlockSchemaCurrent, calendarEventRollingHorizon, createSlotlockStore, readSlotlockSchemaVersion, SLOTLOCK_AGENT_OWNER_COMMAND_QUOTA, SLOTLOCK_AGENT_OWNER_EVENT_QUOTA, SLOTLOCK_CALENDAR_HORIZON_DAYS, SLOTLOCK_EVENT_COMMAND_RETENTION_DAYS, SLOTLOCK_INTERNAL_EVENT_OWNER_REF, SLOTLOCK_LOCAL_RECURRENCE_COVERAGE_SOURCE, SLOTLOCK_MATERIALIZATION_WINDOW_DAYS, SLOTLOCK_MAX_EVENT_DURATION_DAYS, SLOTLOCK_TENANT_WRITE_METHODS, } from './store.js';
package/interop.d.ts ADDED
@@ -0,0 +1,117 @@
1
+ import type { SlotlockCalendarEvent, WeeklyAvailabilityRule } from './types.js';
2
+ /** The longest VAVAILABILITY text `parseVAvailability` reads. */
3
+ export declare const SLOTLOCK_MAX_VAVAILABILITY_CHARACTERS = 65536;
4
+ export interface EmitVAvailabilityOptions {
5
+ /** The resource's weekly rules, in `timezone`. */
6
+ rules: readonly WeeklyAvailabilityRule[];
7
+ /** The IANA zone the rules are read in: every DTSTART names it as its TZID. */
8
+ timezone: string;
9
+ /** The VAVAILABILITY's UID; each AVAILABLE's is this with its index. */
10
+ uid: string;
11
+ }
12
+ /**
13
+ * A VCALENDAR with one VAVAILABILITY holding an AVAILABLE per rule: DTSTART on the rule's first day
14
+ * in a reference week of January 2024, with the IANA zone as TZID (no VTIMEZONE: RFC 7809 lets the
15
+ * two sides agree on IANA names), DURATION and the rule's RRULE. `[]` is a VAVAILABILITY with no
16
+ * AVAILABLE: never bookable. CRLF line endings, folded at 75 octets.
17
+ */
18
+ export declare function emitVAvailability({ rules, timezone, uid }: EmitVAvailabilityOptions): string;
19
+ export interface ParsedVAvailability {
20
+ /** The TZID every AVAILABLE named, `UTC` for UTC times, or null when they are all floating. */
21
+ timezone: string | null;
22
+ rules: WeeklyAvailabilityRule[];
23
+ }
24
+ /**
25
+ * Weekly rules from an iCalendar VAVAILABILITY (RFC 7953): one VAVAILABILITY, each AVAILABLE a
26
+ * weekly RRULE with a time of day and a length. Refuses (`invalid_availability`) what weekly
27
+ * rules cannot say: a VAVAILABILITY bounded by DTSTART or DTEND, more than one, an AVAILABLE
28
+ * without RRULE, with RDATE, EXDATE or RECURRENCE-ID, a whole-day DTSTART, seconds, AVAILABLEs in
29
+ * different zones, and any rule `parseAvailabilityRules` refuses. An RRULE without BYDAY takes
30
+ * DTSTART's day, as RFC 5545 reads it.
31
+ */
32
+ export declare function parseVAvailability(text: string): ParsedVAvailability;
33
+ /** A JSCalendar Event object (RFC 8984 §5.1): the properties Slotlock fills. */
34
+ export interface JSCalendarEvent {
35
+ '@type': 'Event';
36
+ uid: string;
37
+ updated: string;
38
+ created: string;
39
+ sequence: number;
40
+ prodId: string;
41
+ title: string;
42
+ description?: string;
43
+ start: string;
44
+ timeZone: string;
45
+ duration: string;
46
+ status: 'confirmed' | 'tentative';
47
+ freeBusyStatus: 'free' | 'busy';
48
+ locations?: Record<string, {
49
+ '@type': 'Location';
50
+ name: string;
51
+ }>;
52
+ participants?: Record<string, JSCalendarParticipant>;
53
+ alerts?: Record<string, JSCalendarAlert>;
54
+ recurrenceRules?: JSCalendarRecurrenceRule[];
55
+ recurrenceOverrides?: Record<string, {
56
+ excluded: true;
57
+ } | {
58
+ start: string;
59
+ duration: string;
60
+ }>;
61
+ /** The RRULE the recurrence was written as, kept verbatim (RFC 8984 §3.3 vendor property). */
62
+ 'slotlock.pylota.io:rrule'?: string;
63
+ }
64
+ export interface JSCalendarParticipant {
65
+ '@type': 'Participant';
66
+ name?: string;
67
+ email: string;
68
+ sendTo: {
69
+ imip: string;
70
+ };
71
+ roles: Record<string, true>;
72
+ participationStatus?: 'needs-action' | 'accepted' | 'declined' | 'tentative' | 'delegated';
73
+ expectReply?: boolean;
74
+ }
75
+ export interface JSCalendarAlert {
76
+ '@type': 'Alert';
77
+ trigger: {
78
+ '@type': 'OffsetTrigger';
79
+ offset: string;
80
+ relativeTo: 'start';
81
+ };
82
+ action: 'display' | 'email';
83
+ }
84
+ export interface JSCalendarRecurrenceRule {
85
+ '@type': 'RecurrenceRule';
86
+ frequency: 'yearly' | 'monthly' | 'weekly' | 'daily' | 'hourly' | 'minutely' | 'secondly';
87
+ interval?: number;
88
+ firstDayOfWeek?: string;
89
+ byDay?: {
90
+ '@type': 'NDay';
91
+ day: string;
92
+ nthOfPeriod?: number;
93
+ }[];
94
+ byMonthDay?: number[];
95
+ byMonth?: string[];
96
+ byYearDay?: number[];
97
+ byWeekNo?: number[];
98
+ byHour?: number[];
99
+ byMinute?: number[];
100
+ bySecond?: number[];
101
+ bySetPosition?: number[];
102
+ count?: number;
103
+ until?: string;
104
+ }
105
+ /**
106
+ * An RRULE as a JSCalendar RecurrenceRule (RFC 8984 §4.3.3), or null when it holds a part the
107
+ * mapping does not know (the verbatim RRULE is exported beside it either way). A UTC UNTIL becomes
108
+ * the wall time in `timezone`; a date UNTIL the end of that day.
109
+ */
110
+ export declare function recurrenceRuleFromRRule(rrule: string, timezone: string): JSCalendarRecurrenceRule | null;
111
+ /**
112
+ * A Slotlock calendar event as a JSCalendar Event (RFC 8984): its id as `uid`, its revision as
113
+ * `sequence`, start as a LocalDateTime in its zone with an exact duration, the organizer an
114
+ * `owner` participant, reminders `OffsetTrigger` alerts before the start, and the recurrence as
115
+ * `recurrenceRules` with `recurrenceOverrides` keyed by each exception's original start.
116
+ */
117
+ export declare function toJSCalendarEvent(event: SlotlockCalendarEvent): JSCalendarEvent;