slotlock 0.1.0 → 0.2.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 +138 -0
- package/CONTRIBUTING.md +35 -9
- package/README.md +153 -79
- package/SECURITY.md +40 -4
- package/SPEC.md +19 -6
- package/agent-server.d.ts +64 -7
- package/agent-server.js +273 -68
- package/agent-store-backend.d.ts +16 -0
- package/agent-store-backend.js +257 -2
- package/api-keys.d.ts +11 -4
- package/api-keys.js +9 -2
- package/application-api.d.ts +54 -0
- package/application-api.js +290 -0
- package/dashboard.d.ts +4 -1
- package/dashboard.js +6 -4
- package/ddl.d.ts +2 -1
- package/ddl.js +143 -15
- package/hooks.d.ts +7 -0
- package/hooks.js +13 -0
- package/index.d.ts +8 -4
- package/index.js +4 -2
- package/maintenance.d.ts +57 -0
- package/maintenance.js +181 -0
- package/node-server.js +121 -5
- package/package.json +1 -1
- package/rest-api.d.ts +33 -18
- package/rest-api.js +131 -63
- package/rules.d.ts +19 -0
- package/rules.js +32 -4
- package/self-host.d.ts +5 -2
- package/self-host.js +127 -20
- package/slotlock.manifest.json +1 -1
- package/store.d.ts +30 -8
- package/store.js +69 -27
- package/sync.js +530 -49
- package/timezone.d.ts +19 -0
- package/timezone.js +16 -1
- package/types.d.ts +4 -1
- package/weekly-hours.js +2 -2
package/SPEC.md
CHANGED
|
@@ -129,19 +129,29 @@ event, an exhausted quota) is a result, not a protocol error:
|
|
|
129
129
|
- A2A returns the agent's reply message with one `application/json` data part holding the result or
|
|
130
130
|
`{"error":{"code":"…"}}`.
|
|
131
131
|
|
|
132
|
-
|
|
132
|
+
A body must be `application/json`, compared without regard to case (RFC 9110 §8.3.1), or the request
|
|
133
|
+
is HTTP 415; one longer than the server's limit is HTTP 413, refused as soon as it passes the limit,
|
|
134
|
+
whether or not it declares a `Content-Length`.
|
|
135
|
+
|
|
136
|
+
Protocol errors stay in the protocol. MCP: an unknown tool, or `arguments` that are not an object
|
|
137
|
+
(left out or null is none), is JSON-RPC `-32602`, a server fault
|
|
133
138
|
(including backend output that violates the declared schema) is `-32603` with HTTP 500, and a
|
|
134
139
|
missing or unsupported `MCP-Protocol-Version` header is HTTP 400. A 2026-07-28 request is checked in
|
|
135
140
|
that revision's order, each failure HTTP 400: a missing or malformed `_meta` field is `-32602`, an
|
|
136
141
|
`MCP-Protocol-Version`, `Mcp-Method` or (Base64-sentinel-decoded) `Mcp-Name` that disagrees with the
|
|
137
142
|
body is `-32020`, and an unimplemented revision is `-32022` naming the supported ones. An
|
|
138
143
|
unimplemented method is HTTP 404 `-32601`; a rate-limited request is HTTP 429 `-31029`, outside the
|
|
139
|
-
`-32020`..`-32099` range that revision reserves. A2A: every JSON-RPC error travels
|
|
140
|
-
|
|
141
|
-
|
|
144
|
+
`-32020`..`-32099` range that revision reserves. A2A: every JSON-RPC error travels in an HTTP 200
|
|
145
|
+
envelope (a body over the size limit is HTTP 413); A2A's own errors, below, carry a
|
|
146
|
+
`google.rpc.ErrorInfo` detail and JSON-RPC's (`-32700`, `-32600`, `-32601`, `-32603`) none. An
|
|
147
|
+
`A2A-Version` other than `1.0`, including none (read as 0.3), is `VersionNotSupportedError`
|
|
148
|
+
(`-32009`); push-notification methods are
|
|
142
149
|
`PushNotificationNotSupportedError` (`-32003`); streaming, task subscription and the extended card
|
|
143
150
|
are `UnsupportedOperationError` (`-32004`); a message that is not exactly one data part
|
|
144
|
-
`{"skill": "<id>", "arguments": {…}}`
|
|
151
|
+
`{"skill": "<id>", "arguments": {…}}` (`arguments` left out or null is none; any other value that is
|
|
152
|
+
not an object is not arguments) is `-32602`, as is a `configuration` or `metadata` that is set but
|
|
153
|
+
is not an object; a rate-limited request is `-32029` with the reason `RATE_LIMITED` and a null id,
|
|
154
|
+
answered before its body is read. The server replies with messages and keeps no
|
|
145
155
|
tasks, so the core task operations answer as for an unknown task: `GetTask` and `CancelTask` are
|
|
146
156
|
`TaskNotFoundError` (`-32001`), `ListTasks` returns an empty page (`pageSize` 1-100, default 50).
|
|
147
157
|
Their params are checked first, as `SendMessage`'s are: a field the method does not define, a
|
|
@@ -237,4 +247,7 @@ rejects absolute-form request targets, applies finite header/body/handler and co
|
|
|
237
247
|
propagates disconnects through `AbortSignal`, and force-closes only after a bounded graceful-shutdown
|
|
238
248
|
window. When it closes it first asks the target to end long-lived responses (the agent server's
|
|
239
249
|
`shutdown()`), and closes keep-alive connections whose response finished during shutdown. It exposes
|
|
240
|
-
sanitized transport failures and leaves public TLS termination to the deployment.
|
|
250
|
+
sanitized transport failures and leaves public TLS termination to the deployment. A body the target
|
|
251
|
+
stops reading (one past its size limit) does not abort the request: once the response is written,
|
|
252
|
+
the rest is discarded as it arrives, within `requestTimeout`. Closing the adapter while it is still
|
|
253
|
+
starting rejects the pending `listen()` with `listen_aborted`.
|
package/agent-server.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type SlotlockTraceContext } from './mcp-modern.js';
|
|
2
|
+
import { type SlotlockApplicationBackend, type SlotlockApplicationOperation } from './application-api.js';
|
|
2
3
|
export type { SlotlockTraceContext } from './mcp-modern.js';
|
|
3
4
|
export { clientSupportsSlotlockMcpApp, SLOTLOCK_MCP_APP_HTML, SLOTLOCK_MCP_APP_MIME_TYPE, SLOTLOCK_MCP_APP_RESOURCE, SLOTLOCK_MCP_APP_RESOURCE_URI, SLOTLOCK_MCP_APPS_EXTENSION, } from './mcp-app.js';
|
|
4
5
|
/**
|
|
@@ -163,10 +164,31 @@ export type SlotlockAgentServerEvent = {
|
|
|
163
164
|
operation: SlotlockAgentOperation;
|
|
164
165
|
outcome: 'requested' | 'accepted' | 'declined' | 'cancelled' | 'expired' | 'refused' | 'unavailable';
|
|
165
166
|
} | {
|
|
166
|
-
/**
|
|
167
|
+
/**
|
|
168
|
+
* A REST call that named an operation, and the HTTP status it answered: run, or refused before
|
|
169
|
+
* it ran (a body that is not JSON, too large or not an object).
|
|
170
|
+
*/
|
|
167
171
|
type: 'rest';
|
|
168
|
-
operation: SlotlockAgentOperation;
|
|
172
|
+
operation: SlotlockAgentOperation | SlotlockApplicationOperation;
|
|
169
173
|
status: number;
|
|
174
|
+
/** How long the call took from naming its operation, in milliseconds to a tenth. */
|
|
175
|
+
durationMs: number;
|
|
176
|
+
/** The W3C trace id of the call's valid `traceparent`, when it carried one. */
|
|
177
|
+
traceId?: string;
|
|
178
|
+
} | {
|
|
179
|
+
/** An MCP `tools/call` or A2A `SendMessage` that named an operation, and how it ended. */
|
|
180
|
+
type: 'call';
|
|
181
|
+
protocol: 'mcp' | 'a2a';
|
|
182
|
+
operation: SlotlockAgentOperation;
|
|
183
|
+
/**
|
|
184
|
+
* `ok`, or the refusal's code (`overlap`, `forbidden`, `rate_limited`, …), or why the request
|
|
185
|
+
* was refused before the operation ran: `invalid_arguments` (MCP arguments that are not an
|
|
186
|
+
* object), `missing_capability` (a guarded write from a 2026-07-28 client without form
|
|
187
|
+
* elicitation), `invalid_message` or `invalid_message_parameters` (A2A).
|
|
188
|
+
*/
|
|
189
|
+
outcome: string;
|
|
190
|
+
durationMs: number;
|
|
191
|
+
traceId?: string;
|
|
170
192
|
} | {
|
|
171
193
|
type: 'subscription';
|
|
172
194
|
outcome: 'opened' | 'closed';
|
|
@@ -204,6 +226,21 @@ export interface SlotlockAgentServerOptions {
|
|
|
204
226
|
* to ask a person. Off unless set.
|
|
205
227
|
*/
|
|
206
228
|
rest?: boolean;
|
|
229
|
+
/**
|
|
230
|
+
* Also serve the application API under `/v1` (application-api.ts): resources, bookable hours,
|
|
231
|
+
* holds, reservations, calendar coverage and maintenance, for the application around the agents,
|
|
232
|
+
* in any language. Needs `rest`. A principal whose `scopes` are set needs `admin`
|
|
233
|
+
* (SLOTLOCK_APPLICATION_SCOPE); then `authorize` decides. They are never MCP tools or A2A skills,
|
|
234
|
+
* and never wait for a confirmation. Off unless set.
|
|
235
|
+
*/
|
|
236
|
+
application?: {
|
|
237
|
+
backend: SlotlockApplicationBackend;
|
|
238
|
+
authorize(args: {
|
|
239
|
+
principal: SlotlockAgentPrincipal;
|
|
240
|
+
operation: SlotlockApplicationOperation;
|
|
241
|
+
input: Record<string, unknown>;
|
|
242
|
+
}): Promise<boolean>;
|
|
243
|
+
};
|
|
207
244
|
/** Require a person's confirmation before the listed writes run. Off unless set. */
|
|
208
245
|
confirmation?: SlotlockAgentConfirmationOptions;
|
|
209
246
|
/**
|
|
@@ -218,23 +255,24 @@ export interface SlotlockAgentServerOptions {
|
|
|
218
255
|
*/
|
|
219
256
|
subscriptions?: SlotlockAgentSubscriptionOptions | false;
|
|
220
257
|
/**
|
|
221
|
-
* Observe confirmations and subscriptions (counts and outcomes, no arguments or
|
|
222
|
-
* metrics or audit. It
|
|
258
|
+
* Observe calls, confirmations and subscriptions (counts and outcomes, no arguments or
|
|
259
|
+
* identities) for metrics or audit. It is not awaited, and whatever it throws, or its promise
|
|
260
|
+
* rejects with, is ignored.
|
|
223
261
|
*/
|
|
224
262
|
onEvent?: (event: SlotlockAgentServerEvent) => void;
|
|
225
263
|
/**
|
|
226
264
|
* Called with a failure no client is told about: an operation's backend threw something other
|
|
227
265
|
* than a `SlotlockAgentOperationError`, or returned a result outside the operation's schema. The
|
|
228
266
|
* client gets `internal_error` and nothing more, so log it here to find out why. It receives the
|
|
229
|
-
* error and the operation, never the arguments or the request
|
|
230
|
-
*
|
|
267
|
+
* error and the operation, never the arguments or the request. It is not awaited, and whatever it
|
|
268
|
+
* throws, or its promise rejects with, is ignored.
|
|
231
269
|
*/
|
|
232
270
|
onError?: (error: unknown, context: SlotlockAgentErrorContext) => void;
|
|
233
271
|
}
|
|
234
272
|
/** What `onError` is told about an unexpected failure besides the error itself. */
|
|
235
273
|
export interface SlotlockAgentErrorContext {
|
|
236
274
|
/** The operation that failed; `null` when the failure came before one was resolved. */
|
|
237
|
-
operation: SlotlockAgentOperation | null;
|
|
275
|
+
operation: SlotlockAgentOperation | SlotlockApplicationOperation | null;
|
|
238
276
|
}
|
|
239
277
|
export interface SlotlockAgentOperationDispatchOptions {
|
|
240
278
|
backend: SlotlockAgentCalendarBackend;
|
|
@@ -309,6 +347,25 @@ export declare function slotlockMcpToolResult(outcome: {
|
|
|
309
347
|
code: string;
|
|
310
348
|
details?: Readonly<Record<string, string | number | boolean | null>>;
|
|
311
349
|
}): SlotlockMcpToolResult;
|
|
350
|
+
/** The application operations with their input and output as JSON Schema, as REST serves them. */
|
|
351
|
+
export declare function slotlockApplicationOperations(): {
|
|
352
|
+
name: SlotlockApplicationOperation;
|
|
353
|
+
title: string;
|
|
354
|
+
description: string;
|
|
355
|
+
method: "DELETE" | "GET" | "POST" | "PUT";
|
|
356
|
+
path: string;
|
|
357
|
+
inputSchema: Readonly<Record<string, unknown>>;
|
|
358
|
+
outputSchema: Readonly<Record<string, unknown>>;
|
|
359
|
+
}[];
|
|
360
|
+
/**
|
|
361
|
+
* The OpenAPI 3.1 document of the REST API: what a server with `rest` (and `application`) serves at
|
|
362
|
+
* /openapi.json. Without `publicBaseUrl` the server URL is a variable, `{baseUrl}`, as in the
|
|
363
|
+
* repository's openapi.json, which client generators read.
|
|
364
|
+
*/
|
|
365
|
+
export declare function slotlockOpenApi(options?: {
|
|
366
|
+
publicBaseUrl?: string;
|
|
367
|
+
application?: boolean;
|
|
368
|
+
}): Record<string, unknown>;
|
|
312
369
|
export declare function slotlockAgentTools(): {
|
|
313
370
|
name: "slotlock_create_event" | "slotlock_delete_event" | "slotlock_find_next_available" | "slotlock_get_event" | "slotlock_get_free_busy" | "slotlock_list_events" | "slotlock_list_resources" | "slotlock_update_event";
|
|
314
371
|
title: "Create resource event" | "Delete resource event" | "Find next available interval" | "Get free-busy" | "Get resource event" | "List calendar resources" | "List resource events" | "Update resource event";
|