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/dashboard.d.ts
CHANGED
|
@@ -1,19 +1,28 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import { type
|
|
1
|
+
import type { SlotlockDashboardTeams } from './teams.js';
|
|
2
|
+
import { type SlotlockApiKeyStore } from './api-keys.js';
|
|
3
|
+
import { type SlotlockAgentCalendarBackend, type SlotlockAgentOperation, type SlotlockAgentOperationDispatchOptions, type SlotlockAgentPrincipal, type SlotlockAgentUsage } from './agent-server.js';
|
|
3
4
|
import { type SlotlockAssistantStore } from './assistant.js';
|
|
4
5
|
import { type SlotlockRate } from './config.js';
|
|
5
6
|
import { type SlotlockBookingRules } from './booking-rules.js';
|
|
7
|
+
import { type SlotlockTenantPlan } from './plans.js';
|
|
8
|
+
import { type SlotlockLocation, type SlotlockResourceGroup, type SlotlockResourceProfileInput } from './resource-profile.js';
|
|
9
|
+
import { type SlotlockUsageRow } from './usage.js';
|
|
6
10
|
import { type CreateWebhookEndpointResult, type SlotlockChange, type SlotlockWebhookEndpoint } from './event-feed.js';
|
|
7
11
|
import type { SlotlockSql, SlotlockStore, SlotlockWaitlistEntry } from './store.js';
|
|
8
|
-
import
|
|
12
|
+
import { type SlotlockSandboxScenario } from './sandbox.js';
|
|
13
|
+
import type { Interval, SlotlockAgendaEntry, SlotlockApproval, SlotlockResource, SlotlockBookingRuleDefaults, WeeklyAvailabilityRule } from './types.js';
|
|
9
14
|
/** Resources one dashboard tenant may hold. */
|
|
10
|
-
export declare const SLOTLOCK_DASHBOARD_MAX_RESOURCES =
|
|
15
|
+
export declare const SLOTLOCK_DASHBOARD_MAX_RESOURCES = 500;
|
|
11
16
|
/**
|
|
12
17
|
* A tenant's calendar resources, as the dashboard lists and adds them. Each write takes, last, the
|
|
13
18
|
* person who made it (`github:<user id>`) as `actor`, to record on the event feed.
|
|
14
19
|
*/
|
|
15
20
|
export interface SlotlockDashboardResources {
|
|
16
21
|
list(tenantRef: string): Promise<SlotlockResource[]>;
|
|
22
|
+
/** How many resources the tenant has, archived ones included, as a resource limit counts them. */
|
|
23
|
+
count?(tenantRef: string): Promise<number>;
|
|
24
|
+
/** The tenant's metered usage from `from` to `to`, UTC days inclusive (usage.ts). */
|
|
25
|
+
usage?(tenantRef: string, from: string, to: string): Promise<SlotlockUsageRow[]>;
|
|
17
26
|
/**
|
|
18
27
|
* Create the resource, or re-zone the tenant's resource with that reference. Refuse a new one
|
|
19
28
|
* (an error with `code: 'resource_limit_reached'`) once the tenant has
|
|
@@ -39,8 +48,84 @@ export interface SlotlockDashboardResources {
|
|
|
39
48
|
setRules?(tenantRef: string, id: string, rules: SlotlockBookingRules | null, actor?: string): Promise<SlotlockResource | null>;
|
|
40
49
|
/** The tenant's default booking rules and its pools', which a resource's own rules overlay. */
|
|
41
50
|
ruleDefaults?(tenantRef: string): Promise<SlotlockBookingRuleDefaults>;
|
|
51
|
+
/**
|
|
52
|
+
* Change one of the tenant's resources' profile (resource-profile.ts): the fields given, keeping
|
|
53
|
+
* the rest. As setRules; `code: 'invalid_resource_profile'`, with the `field`.
|
|
54
|
+
*/
|
|
55
|
+
setProfile?(tenantRef: string, id: string, profile: SlotlockResourceProfileInput, actor?: string): Promise<SlotlockResource | null>;
|
|
56
|
+
/**
|
|
57
|
+
* Make one of the tenant's resources a part of a composite (RFC 0003 G8), or no part. A refusal
|
|
58
|
+
* carries the store's `code`: `parent_not_found`, `composite_too_deep`, `composite_parts_limit`
|
|
59
|
+
* or `composite_busy`.
|
|
60
|
+
*/
|
|
61
|
+
setParent?(tenantRef: string, id: string, parentId: string | null, actor?: string): Promise<SlotlockResource | null>;
|
|
42
62
|
/** Put one of the tenant's resources in a pool, or none: as setRules; `code: 'invalid_pool'`. */
|
|
43
63
|
setPool?(tenantRef: string, id: string, pool: string | null, actor?: string): Promise<SlotlockResource | null>;
|
|
64
|
+
/**
|
|
65
|
+
* The tenant's locations and groups (RFC 0003 G2, G3), and where each resource is in them. A
|
|
66
|
+
* refusal carries the store's `code`: `invalid_location` or `invalid_group` (with the `field`),
|
|
67
|
+
* `location_not_found`, `location_too_deep`, `location_cycle`, `location_limit_reached`,
|
|
68
|
+
* `location_in_use`, `group_not_found`, `group_limit_reached` or `resource_group_limit_reached`.
|
|
69
|
+
*/
|
|
70
|
+
grouping?: {
|
|
71
|
+
/** Each under its parent, depth first, with how many resources are at each. */
|
|
72
|
+
locations(tenantRef: string): Promise<SlotlockLocation[]>;
|
|
73
|
+
/** Create the location with this reference, or change its name, parent and time zone. */
|
|
74
|
+
putLocation(tenantRef: string, location: {
|
|
75
|
+
ref: string;
|
|
76
|
+
name: string;
|
|
77
|
+
parentRef: string | null;
|
|
78
|
+
timezone: string | null;
|
|
79
|
+
}, actor?: string): Promise<SlotlockLocation>;
|
|
80
|
+
/** False when the tenant has no such location. */
|
|
81
|
+
deleteLocation(tenantRef: string, ref: string, actor?: string): Promise<boolean>;
|
|
82
|
+
/** By reference, with how many resources are in each. */
|
|
83
|
+
groups(tenantRef: string): Promise<SlotlockResourceGroup[]>;
|
|
84
|
+
/** Create the group with this reference, or change its name and description. */
|
|
85
|
+
putGroup(tenantRef: string, group: {
|
|
86
|
+
ref: string;
|
|
87
|
+
name: string;
|
|
88
|
+
description: string | null;
|
|
89
|
+
}, actor?: string): Promise<SlotlockResourceGroup>;
|
|
90
|
+
/** Delete a group, its resources left as they are: false when the tenant has no such group. */
|
|
91
|
+
deleteGroup(tenantRef: string, ref: string, actor?: string): Promise<boolean>;
|
|
92
|
+
/**
|
|
93
|
+
* Put one of the tenant's resources at a location (or none) and in exactly these groups, in one
|
|
94
|
+
* transaction: the resource as it then is, or null when it is not the tenant's.
|
|
95
|
+
*/
|
|
96
|
+
place(tenantRef: string, id: string, place: {
|
|
97
|
+
location: string | null;
|
|
98
|
+
groups: readonly string[];
|
|
99
|
+
}, actor?: string): Promise<SlotlockResource | null>;
|
|
100
|
+
};
|
|
101
|
+
/**
|
|
102
|
+
* The tenant's approvals (RFC 0004 A4), newest first, and deciding one: a grant makes the booking
|
|
103
|
+
* as the agent asked for it; a refusal says why (approval_not_pending, overlap, a booking rule).
|
|
104
|
+
*/
|
|
105
|
+
approvals?: {
|
|
106
|
+
list(tenantRef: string, limit: number): Promise<SlotlockApproval[]>;
|
|
107
|
+
decide(tenantRef: string, id: string, decision: 'grant' | 'decline', actor?: string, reason?: string): Promise<{
|
|
108
|
+
ok: true;
|
|
109
|
+
} | {
|
|
110
|
+
ok: false;
|
|
111
|
+
code: string;
|
|
112
|
+
}>;
|
|
113
|
+
};
|
|
114
|
+
/**
|
|
115
|
+
* The sandbox (RFC 0004 A6), for a test environment only: fill it with a scenario, empty it, and
|
|
116
|
+
* make what would lapse within some minutes lapse now. Each refuses a live tenant.
|
|
117
|
+
*/
|
|
118
|
+
sandbox?: {
|
|
119
|
+
seed(tenantRef: string, scenario: SlotlockSandboxScenario): Promise<{
|
|
120
|
+
resources: number;
|
|
121
|
+
bookings: number;
|
|
122
|
+
}>;
|
|
123
|
+
reset(tenantRef: string): Promise<void>;
|
|
124
|
+
fastForward(tenantRef: string, minutes: number): Promise<{
|
|
125
|
+
holds: number;
|
|
126
|
+
approvals: number;
|
|
127
|
+
}>;
|
|
128
|
+
};
|
|
44
129
|
/** The tenant's waitlist, oldest first, and leaving it (false when the entry is not the tenant's). */
|
|
45
130
|
waitlist?: {
|
|
46
131
|
list(tenantRef: string, limit: number): Promise<SlotlockWaitlistEntry[]>;
|
|
@@ -91,6 +176,18 @@ export interface SlotlockDashboardState {
|
|
|
91
176
|
export interface SlotlockDashboardAssistantOptions {
|
|
92
177
|
/** Seals each tenant's API key (SLOTLOCK_ASSISTANT_SECRET): 32+ random characters. */
|
|
93
178
|
secret: string;
|
|
179
|
+
/**
|
|
180
|
+
* Secrets keys may still be sealed under (SLOTLOCK_ASSISTANT_PREVIOUS_SECRETS), newest first, at
|
|
181
|
+
* most SLOTLOCK_ASSISTANT_MAX_PREVIOUS_SECRETS: a key one of them opens is used, and sealed again
|
|
182
|
+
* under `secret` in the same request, so changing the secret makes no owner enter a key again.
|
|
183
|
+
* Drop an old secret once every tenant has used the assistant since the change, or keys still
|
|
184
|
+
* sealed under it stop opening.
|
|
185
|
+
*/
|
|
186
|
+
previousSecrets?: readonly string[];
|
|
187
|
+
/** Each operation the assistant runs, for usage metering (the agent server's `onUsage`). */
|
|
188
|
+
onUsage?: (usage: SlotlockAgentUsage) => void;
|
|
189
|
+
/** Each message a member sends that the assistant answers, for usage metering. Never awaited. */
|
|
190
|
+
onMessage?: (tenantRef: string) => void;
|
|
94
191
|
backend: SlotlockAgentCalendarBackend;
|
|
95
192
|
/**
|
|
96
193
|
* As the agent server's: false refuses an operation. Every offered operation by default. It also
|
|
@@ -135,11 +232,70 @@ export interface SlotlockDashboardAssistantOptions {
|
|
|
135
232
|
/** How long a conversation is kept after its last message: 2 hours by default. */
|
|
136
233
|
conversationTtlMs?: number;
|
|
137
234
|
}
|
|
235
|
+
/**
|
|
236
|
+
* Hosted Slotlock's plans (plans.ts) and their billing: a Plan page with the tenant's plan and use,
|
|
237
|
+
* Upgrade (to a checkout page) and Manage (to a billing portal). Off unless set.
|
|
238
|
+
*/
|
|
239
|
+
export interface SlotlockDashboardBilling {
|
|
240
|
+
/** The tenant's plan (its own, or the default), or null when it has none (the server's limits apply). */
|
|
241
|
+
plan(tenantRef: string): Promise<SlotlockTenantPlan | null>;
|
|
242
|
+
/**
|
|
243
|
+
* Puts a tenant new to plans on the default plan before it adds a key, resource or webhook
|
|
244
|
+
* endpoint, while the default does not yet apply to every tenant (plans.ts).
|
|
245
|
+
*/
|
|
246
|
+
enrol?(tenantRef: string): Promise<void>;
|
|
247
|
+
/** A checkout URL for the Developer plan, or the Team plan for an organization (with `teamPrices`). */
|
|
248
|
+
checkout(input: {
|
|
249
|
+
tenantRef: string;
|
|
250
|
+
interval: 'month' | 'year';
|
|
251
|
+
plan?: 'developer' | 'team';
|
|
252
|
+
customer: string | null;
|
|
253
|
+
successUrl: string;
|
|
254
|
+
cancelUrl: string;
|
|
255
|
+
}): Promise<string>;
|
|
256
|
+
/** A billing portal URL for the tenant's customer. */
|
|
257
|
+
portal(input: {
|
|
258
|
+
customer: string;
|
|
259
|
+
returnUrl: string;
|
|
260
|
+
}): Promise<string>;
|
|
261
|
+
/** The Developer plan's prices as shown, such as `$10`. */
|
|
262
|
+
prices: {
|
|
263
|
+
month: string;
|
|
264
|
+
year: string;
|
|
265
|
+
};
|
|
266
|
+
/**
|
|
267
|
+
* The Team plan's prices as shown (Teams on Cloud). With them, an organization's workspace is
|
|
268
|
+
* offered Team instead of Developer.
|
|
269
|
+
*/
|
|
270
|
+
teamPrices?: {
|
|
271
|
+
month: string;
|
|
272
|
+
year: string;
|
|
273
|
+
};
|
|
274
|
+
/**
|
|
275
|
+
* Metered overage on Developer (SLOTLOCK_OVERAGE, overage.ts): its price as shown, such as `$2
|
|
276
|
+
* per 10,000 operations`, and the percent of the quota where use is refused.
|
|
277
|
+
*/
|
|
278
|
+
overage?: {
|
|
279
|
+
price: string;
|
|
280
|
+
stopPercent: number;
|
|
281
|
+
};
|
|
282
|
+
/** Where a Custom (self-hosted) enquiry goes: an https or mailto URL. */
|
|
283
|
+
contact: string;
|
|
284
|
+
/** The https origins Upgrade and Manage redirect to, allowed in the policy's form-action. */
|
|
285
|
+
formOrigins: readonly string[];
|
|
286
|
+
}
|
|
138
287
|
export interface SlotlockDashboardOptions {
|
|
139
288
|
/** Where people reach the server; the dashboard lives at `<publicUrl>/dashboard`. */
|
|
140
289
|
publicUrl: string;
|
|
141
290
|
/** What the deployment is called in the dashboard: 1-60 characters. Defaults to `Slotlock`. */
|
|
142
291
|
name?: string;
|
|
292
|
+
/**
|
|
293
|
+
* The terms people accept by signing in, an https URL. The sign-in page links them beside the
|
|
294
|
+
* button; without it, the page names no terms.
|
|
295
|
+
*/
|
|
296
|
+
termsUrl?: string;
|
|
297
|
+
/** The privacy notice the sign-in page links, an https URL. */
|
|
298
|
+
privacyUrl?: string;
|
|
143
299
|
/**
|
|
144
300
|
* Where agents reach the server's MCP and A2A endpoints, which the dashboard shows, when it is
|
|
145
301
|
* served from another origin (on Cloudflare Workers, with the server elsewhere). Defaults to
|
|
@@ -158,9 +314,25 @@ export interface SlotlockDashboardOptions {
|
|
|
158
314
|
userUrl?: string;
|
|
159
315
|
membershipsUrl?: string;
|
|
160
316
|
};
|
|
317
|
+
/**
|
|
318
|
+
* Sign-in with Google (OpenID Connect), beside GitHub, for people without a GitHub account: each
|
|
319
|
+
* is their own tenant, `google:<subject>`. Not offered with a fixed list of `organizations`,
|
|
320
|
+
* which are GitHub's. Its redirect URI is the same `<publicUrl>/dashboard/callback`.
|
|
321
|
+
*/
|
|
322
|
+
google?: {
|
|
323
|
+
clientId: string;
|
|
324
|
+
clientSecret: string;
|
|
325
|
+
authorizeUrl?: string;
|
|
326
|
+
tokenUrl?: string;
|
|
327
|
+
/** Google's signing keys (JWKS); https://www.googleapis.com/oauth2/v3/certs by default. */
|
|
328
|
+
jwksUrl?: string;
|
|
329
|
+
};
|
|
161
330
|
/** Seals sessions and sign-in state and derives CSRF tokens: 32+ random characters. */
|
|
162
331
|
sessionSecret: string;
|
|
163
|
-
/**
|
|
332
|
+
/**
|
|
333
|
+
* GitHub user ids (numbers, as strings) and Google accounts (`google:<subject>`) that may sign in,
|
|
334
|
+
* or `'*'` for every account.
|
|
335
|
+
*/
|
|
164
336
|
allowedUsers: '*' | readonly string[];
|
|
165
337
|
/**
|
|
166
338
|
* GitHub organization ids (numbers, as strings) this dashboard serves. With them, a tenant is an
|
|
@@ -171,8 +343,14 @@ export interface SlotlockDashboardOptions {
|
|
|
171
343
|
* ends access at the next sign-in, at most a session (12 hours) later, and removing an
|
|
172
344
|
* organization from this list signs its sessions out at once. Without it, each person is their
|
|
173
345
|
* own tenant (`github:<id>`).
|
|
346
|
+
*
|
|
347
|
+
* `'enabled'` (Teams on Cloud, with `teams`): each person signs in to their own tenant and may
|
|
348
|
+
* switch to any organization they belong to that an owner turned on, on the Teams page; turning
|
|
349
|
+
* one off ends its use at once.
|
|
174
350
|
*/
|
|
175
|
-
organizations?: readonly string[];
|
|
351
|
+
organizations?: readonly string[] | 'enabled';
|
|
352
|
+
/** The organizations turned on, with `organizations: 'enabled'` (teams.ts). */
|
|
353
|
+
teams?: SlotlockDashboardTeams;
|
|
176
354
|
keys: SlotlockApiKeyStore;
|
|
177
355
|
resources: SlotlockDashboardResources;
|
|
178
356
|
/** Shared by every server behind this origin: see SlotlockDashboardState. */
|
|
@@ -181,6 +359,18 @@ export interface SlotlockDashboardOptions {
|
|
|
181
359
|
availability?: readonly WeeklyAvailabilityRule[];
|
|
182
360
|
/** The chat assistant; off unless set. */
|
|
183
361
|
assistant?: SlotlockDashboardAssistantOptions;
|
|
362
|
+
/** Plans and billing (hosted Slotlock); off unless set. */
|
|
363
|
+
billing?: SlotlockDashboardBilling;
|
|
364
|
+
/**
|
|
365
|
+
* The deployment meters usage (SLOTLOCK_USAGE=on): the Plan page shows this month's, from the
|
|
366
|
+
* resources adapter's `usage`.
|
|
367
|
+
*/
|
|
368
|
+
usage?: boolean;
|
|
369
|
+
/**
|
|
370
|
+
* The deployment holds tenants to their plans' monthly quotas (SLOTLOCK_QUOTAS=on): the Plan page
|
|
371
|
+
* shows this month's use against them, and warns from 80%. Needs `usage`.
|
|
372
|
+
*/
|
|
373
|
+
quotas?: boolean;
|
|
184
374
|
fetch?: typeof fetch;
|
|
185
375
|
now?: () => number;
|
|
186
376
|
/**
|
|
@@ -204,7 +394,13 @@ export interface SlotlockDashboard {
|
|
|
204
394
|
* The dashboard's resources, in the store under each tenant's row-level security. Adds hold the cap
|
|
205
395
|
* in the database (a READ COMMITTED transaction, under a per-tenant lock).
|
|
206
396
|
*/
|
|
207
|
-
export declare function createSlotlockDashboardResources(store: SlotlockStore
|
|
397
|
+
export declare function createSlotlockDashboardResources(store: SlotlockStore, options?: {
|
|
398
|
+
/**
|
|
399
|
+
* The agent backend (`createSlotlockStoreAgentBackend`) a granted approval's booking is made
|
|
400
|
+
* through: with it, the dashboard lists approvals and decides them.
|
|
401
|
+
*/
|
|
402
|
+
agentBackend?: SlotlockAgentCalendarBackend;
|
|
403
|
+
}): SlotlockDashboardResources;
|
|
208
404
|
/**
|
|
209
405
|
* Records accepted write confirmations (`SlotlockAgentConfirmationOptions.consumeAcceptance`) in
|
|
210
406
|
* Postgres, shared by every server on the database: true the first time a confirmation's nonce is
|