@push.rocks/smartjmap 1.0.0 → 2.1.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/.smartconfig.json +5 -2
- package/dist_ts/00_commitinfo_data.js +3 -3
- package/dist_ts/classes.jmapclient.d.ts +43 -13
- package/dist_ts/classes.jmapclient.js +326 -149
- package/dist_ts/classes.jmapserver.d.ts +154 -84
- package/dist_ts/classes.jmapserver.js +1788 -660
- package/dist_ts/classes.memorymailbackend.d.ts +109 -0
- package/dist_ts/classes.memorymailbackend.js +670 -0
- package/dist_ts/index.d.ts +2 -0
- package/dist_ts/index.js +3 -1
- package/dist_ts/interfaces.backend.d.ts +349 -0
- package/dist_ts/interfaces.backend.js +13 -0
- package/npmextra.json +4 -2
- package/package.json +8 -7
- package/readme.hints.md +25 -14
- package/readme.md +149 -18
- package/ts/00_commitinfo_data.ts +2 -2
- package/ts/classes.jmapclient.ts +414 -153
- package/ts/classes.jmapserver.ts +2389 -761
- package/ts/classes.memorymailbackend.ts +850 -0
- package/ts/index.ts +2 -0
- package/ts/interfaces.backend.ts +413 -0
|
@@ -1,110 +1,180 @@
|
|
|
1
|
-
import type
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
export interface
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
1
|
+
import { type IJmapMailBackend, type TJmapPrincipal } from "./interfaces.backend.js";
|
|
2
|
+
/**
|
|
3
|
+
* Semantic capability marker for the bounded streaming-upload server surface.
|
|
4
|
+
* Consumers must check this exact value before relying on streaming backend
|
|
5
|
+
* uploads, upload concurrency limits, Bearer-only challenges, or error mapping.
|
|
6
|
+
*/
|
|
7
|
+
export declare const JMAP_SERVER_STREAMING_API_VERSION: 1;
|
|
8
|
+
/** Options for constructing a JmapServer. */
|
|
9
|
+
export interface IJmapServerOptions {
|
|
10
|
+
/** The storage backend; defaults to a fresh in-memory `MemoryMailBackend`. */
|
|
11
|
+
backend?: IJmapMailBackend;
|
|
12
|
+
/**
|
|
13
|
+
* Resolves an incoming Request to an authenticated principal (return null
|
|
14
|
+
* to reject with 401). Defaults to a static Basic/Bearer registry fed via
|
|
15
|
+
* `addUser`/`addBearerToken`.
|
|
16
|
+
*/
|
|
17
|
+
authenticate?: (request: Request) => Promise<TJmapPrincipal | null>;
|
|
18
|
+
/**
|
|
19
|
+
* WWW-Authenticate challenges advertised on a 401 response. Defaults to
|
|
20
|
+
* Bearer and Basic for the built-in registry. Custom authenticators should
|
|
21
|
+
* list only the schemes they actually accept.
|
|
22
|
+
*/
|
|
23
|
+
authenticationChallenges?: string[];
|
|
24
|
+
/**
|
|
25
|
+
* Absolute base URL (e.g. `https://mail.example.com`) prefixed to the URLs
|
|
26
|
+
* advertised in the session object. Defaults to relative URLs, which JMAP
|
|
27
|
+
* clients resolve against the session resource URL.
|
|
28
|
+
*/
|
|
29
|
+
baseUrl?: string;
|
|
30
|
+
/** Overrides for the limits advertised in the JMAP session and enforced by this server. */
|
|
31
|
+
limits?: Partial<IJmapServerLimits>;
|
|
32
|
+
/**
|
|
33
|
+
* Process-wide upload ceiling across authenticated principals. Must be at
|
|
34
|
+
* least the advertised per-principal maxConcurrentUpload value.
|
|
35
|
+
*/
|
|
36
|
+
maxConcurrentUploadServer?: number;
|
|
37
|
+
/** Maps backend upload failures to an RFC 7807 response instead of a generic 500. */
|
|
38
|
+
mapUploadError?: (error: unknown) => IJmapUploadProblem | null | undefined;
|
|
32
39
|
}
|
|
33
|
-
export interface
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
submissions: Map<string, IJmapServerSubmission>;
|
|
42
|
-
identities: IJmapServerIdentity[];
|
|
43
|
-
state: number;
|
|
44
|
-
changes: IJmapServerChangeEntry[];
|
|
45
|
-
idCounter: number;
|
|
40
|
+
export interface IJmapServerLimits {
|
|
41
|
+
maxSizeUpload: number;
|
|
42
|
+
maxConcurrentUpload: number;
|
|
43
|
+
maxSizeRequest: number;
|
|
44
|
+
maxConcurrentRequests: number;
|
|
45
|
+
maxCallsInRequest: number;
|
|
46
|
+
maxObjectsInGet: number;
|
|
47
|
+
maxObjectsInSet: number;
|
|
46
48
|
}
|
|
47
|
-
export interface
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
textBody?: string;
|
|
54
|
-
htmlBody?: string;
|
|
55
|
-
keywords?: Record<string, boolean>;
|
|
56
|
-
receivedAt?: string;
|
|
57
|
-
attachments?: Array<{
|
|
58
|
-
name: string;
|
|
59
|
-
type: string;
|
|
60
|
-
content: string | Uint8Array;
|
|
61
|
-
}>;
|
|
49
|
+
export interface IJmapUploadProblem {
|
|
50
|
+
status: number;
|
|
51
|
+
type?: string;
|
|
52
|
+
detail: string;
|
|
53
|
+
limit?: string;
|
|
54
|
+
retryAfterSeconds?: number;
|
|
62
55
|
}
|
|
56
|
+
/** The advertised — and enforced — RFC 8620 core limits. */
|
|
57
|
+
export declare const JMAP_SERVER_LIMITS: IJmapServerLimits;
|
|
63
58
|
/**
|
|
64
|
-
* A
|
|
65
|
-
*
|
|
66
|
-
*
|
|
67
|
-
*
|
|
59
|
+
* A JMAP server core (RFC 8620) with the RFC 8621 mail method surface,
|
|
60
|
+
* dispatching all storage into a pluggable `IJmapMailBackend`.
|
|
61
|
+
*
|
|
62
|
+
* The primary API is the web-standard `fetchHandler(request)` — mount it in
|
|
63
|
+
* any Request/Response runtime (Deno, Bun, service workers, Node ≥18). The
|
|
64
|
+
* `start(port)`/`stop()` pair wraps it in a node:http server for convenience.
|
|
65
|
+
*
|
|
66
|
+
* Endpoints: session (`/.well-known/jmap`, `/jmap/session`), API
|
|
67
|
+
* (`/jmap/api`), upload (`/jmap/upload/{accountId}`), download
|
|
68
|
+
* (`/jmap/download/{accountId}/{blobId}/{name}?type=`), and event source
|
|
69
|
+
* (`/jmap/eventsource` — SSE StateChange pushes per RFC 8620 §7.3).
|
|
70
|
+
*
|
|
71
|
+
* With no options this behaves as the offline test helper: an in-memory
|
|
72
|
+
* backend plus a static credential registry (`addUser`/`addBearerToken`).
|
|
68
73
|
*/
|
|
69
74
|
export declare class JmapServer {
|
|
70
|
-
|
|
71
|
-
private
|
|
75
|
+
readonly backend: IJmapMailBackend;
|
|
76
|
+
private options;
|
|
77
|
+
private readonly limits;
|
|
78
|
+
private readonly maxConcurrentUploadServer;
|
|
79
|
+
private registry;
|
|
80
|
+
private httpServer;
|
|
72
81
|
private sockets;
|
|
73
82
|
private eventStreams;
|
|
74
|
-
|
|
83
|
+
private changeFeedUnsubscribe;
|
|
84
|
+
private cleanupErrors;
|
|
85
|
+
private activeApiRequests;
|
|
86
|
+
private activeUploadRequests;
|
|
87
|
+
private activeUploadsByPrincipal;
|
|
88
|
+
private activeNodeRequests;
|
|
89
|
+
private nodeRequestControllers;
|
|
90
|
+
private stopping;
|
|
91
|
+
private authenticationChallenges;
|
|
92
|
+
constructor(options?: IJmapServerOptions);
|
|
93
|
+
/**
|
|
94
|
+
* Registers Basic credentials in the default authenticator's registry.
|
|
95
|
+
* Only consulted when no custom `authenticate` option is set. Account data
|
|
96
|
+
* itself lives in the backend (the memory backend auto-creates accounts).
|
|
97
|
+
*/
|
|
75
98
|
addUser(username: string, password: string): void;
|
|
76
|
-
/** Registers a valid Bearer token for a user. */
|
|
99
|
+
/** Registers a valid Bearer token for a user in the default authenticator. */
|
|
77
100
|
addBearerToken(username: string, token: string): void;
|
|
78
|
-
|
|
79
|
-
/** Seeds an email into a user's mailbox; bumps state and pushes a StateChange. Returns the email id. */
|
|
80
|
-
addEmail(username: string, mailboxName: string, input: IJmapServerEmailInput): string;
|
|
81
|
-
/** Starts the server. Resolves with the bound port (pass 0 for an ephemeral port). */
|
|
101
|
+
/** Starts a node:http server around fetchHandler. Resolves with the bound port (pass 0 for ephemeral). */
|
|
82
102
|
start(port: number): Promise<number>;
|
|
83
|
-
/**
|
|
103
|
+
/**
|
|
104
|
+
* Stops the server: closes all event streams (clearing their ping timers
|
|
105
|
+
* and the backend change-feed subscription), destroys open connections,
|
|
106
|
+
* and closes the node listener when one was started.
|
|
107
|
+
*/
|
|
84
108
|
stop(): Promise<void>;
|
|
85
|
-
|
|
86
|
-
|
|
109
|
+
/**
|
|
110
|
+
* Handles a JMAP request end to end and returns the Response. This is the
|
|
111
|
+
* runtime-agnostic core — mount it directly as a Deno/Bun fetch handler.
|
|
112
|
+
*/
|
|
113
|
+
fetchHandler(request: Request): Promise<Response>;
|
|
114
|
+
private authenticatePrincipal;
|
|
87
115
|
private handleSession;
|
|
116
|
+
private buildUrl;
|
|
88
117
|
private handleApi;
|
|
89
|
-
|
|
90
|
-
|
|
118
|
+
/**
|
|
119
|
+
* Resolves `#argument` ResultReference objects (RFC 8620 §3.7) against the
|
|
120
|
+
* responses of earlier method calls in the same request.
|
|
121
|
+
*/
|
|
122
|
+
private resolveBackReferences;
|
|
91
123
|
private dispatchMethod;
|
|
124
|
+
private requireAccountId;
|
|
92
125
|
private methodMailboxGet;
|
|
93
126
|
private methodMailboxQuery;
|
|
127
|
+
private methodMailboxChanges;
|
|
128
|
+
private methodThreadGet;
|
|
94
129
|
private methodEmailGet;
|
|
130
|
+
/** Applies the Email/get body-value fetch flags and maxBodyValueBytes truncation. */
|
|
131
|
+
private buildBodyValues;
|
|
95
132
|
private methodEmailQuery;
|
|
96
133
|
private methodEmailChanges;
|
|
97
134
|
private methodEmailSet;
|
|
135
|
+
/**
|
|
136
|
+
* Normalizes an Email/set update patch (RFC 8620 §5.3): full `keywords`/
|
|
137
|
+
* `mailboxIds` replacements and single-key JSON-pointer patches
|
|
138
|
+
* (`keywords/$seen`, `mailboxIds/<id>`). Email properties other than these
|
|
139
|
+
* two are immutable (RFC 8621 §4.6).
|
|
140
|
+
*/
|
|
141
|
+
private parseEmailUpdatePatch;
|
|
98
142
|
private methodIdentityGet;
|
|
99
143
|
private methodEmailSubmissionSet;
|
|
100
|
-
|
|
101
|
-
private
|
|
144
|
+
/** Uses the client-provided envelope or derives it from the email's addresses. */
|
|
145
|
+
private resolveEnvelope;
|
|
146
|
+
private cancelRequestBody;
|
|
147
|
+
private readRequestBodyBounded;
|
|
148
|
+
private createExactUploadBody;
|
|
149
|
+
private mappedUploadErrorResponse;
|
|
150
|
+
private requestBodyErrorResponse;
|
|
151
|
+
private handleStreamingUpload;
|
|
152
|
+
private handleUpload;
|
|
153
|
+
private handleDownload;
|
|
154
|
+
private handleEventSource;
|
|
155
|
+
private registerStream;
|
|
156
|
+
private unregisterStream;
|
|
157
|
+
private closeStream;
|
|
158
|
+
private writeToStream;
|
|
159
|
+
/**
|
|
160
|
+
* Pushes a StateChange to matching event streams. Per-type states are
|
|
161
|
+
* deduplicated per stream, so a mutation notified both by the backend
|
|
162
|
+
* change feed and by the post-request push is delivered once.
|
|
163
|
+
*/
|
|
164
|
+
private pushStateChange;
|
|
102
165
|
/**
|
|
103
|
-
*
|
|
104
|
-
*
|
|
166
|
+
* Emits a StateChange after a mutating JMAP request, covering backends
|
|
167
|
+
* whose change feed only reports out-of-band mutations. Deduplicated
|
|
168
|
+
* against feed-driven pushes via the per-stream state tracking.
|
|
105
169
|
*/
|
|
106
|
-
private
|
|
107
|
-
|
|
108
|
-
private
|
|
109
|
-
private
|
|
170
|
+
private pushAfterMutation;
|
|
171
|
+
private nodeRequestBody;
|
|
172
|
+
private handleNodeRequest;
|
|
173
|
+
private validateProperties;
|
|
174
|
+
private projectObject;
|
|
175
|
+
private validatePosition;
|
|
176
|
+
private validateChangesArgs;
|
|
177
|
+
private jsonResponse;
|
|
178
|
+
private problemResponse;
|
|
179
|
+
private limitResponse;
|
|
110
180
|
}
|