@dxos/plugin-jmap 0.12.0-next-73daef452f1464b62efdbca75fb0067c1066f264 → 0.13.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/dist/lib/JmapOperationHandlerSet.mjs.map +1 -1
- package/dist/lib/apis.mjs +3 -3
- package/dist/lib/apis.mjs.map +1 -1
- package/dist/lib/capabilities.browser.mjs +19 -0
- package/dist/lib/capabilities.browser.mjs.map +1 -0
- package/dist/lib/capabilities.mjs.map +1 -1
- package/dist/lib/capabilities.node.mjs.map +1 -1
- package/dist/lib/capabilities.tauri.mjs +19 -0
- package/dist/lib/capabilities.tauri.mjs.map +1 -0
- package/dist/lib/capabilities.workerd.mjs.map +1 -1
- package/dist/lib/chunk-connector.mjs +9 -9
- package/dist/lib/chunk-connector.mjs.map +1 -1
- package/dist/lib/chunk-errors.mjs +3 -1
- package/dist/lib/chunk-errors.mjs.map +1 -1
- package/dist/lib/chunk-handler.mjs +2 -2
- package/dist/lib/chunk-handler.mjs.map +1 -1
- package/dist/lib/chunk-mail-send.mjs.map +1 -1
- package/dist/lib/chunk-operation-handler.mjs +1 -1
- package/dist/lib/chunk-send.mjs +6 -5
- package/dist/lib/chunk-send.mjs.map +1 -1
- package/dist/lib/chunk-sync-provider.mjs +5 -5
- package/dist/lib/chunk-sync-provider.mjs.map +1 -1
- package/dist/lib/chunk-sync.mjs +3 -3
- package/dist/lib/chunk-sync.mjs.map +1 -1
- package/dist/lib/index.mjs +2 -4
- package/dist/lib/meta.mjs.map +1 -1
- package/dist/lib/services.mjs.map +1 -1
- package/dist/lib/testing.mjs +2 -2
- package/dist/lib/testing.mjs.map +1 -1
- package/dist/types/src/JmapPlugin.workerd.test.d.ts +2 -0
- package/dist/types/src/JmapPlugin.workerd.test.d.ts.map +1 -0
- package/dist/types/src/apis/Jmap/api.d.ts +4 -4
- package/dist/types/src/apis/Jmap/api.d.ts.map +1 -1
- package/dist/types/src/apis/Jmap/index.d.ts +2 -2
- package/dist/types/src/apis/Jmap/index.d.ts.map +1 -1
- package/dist/types/src/apis/JmapMail/api.d.ts +4 -4
- package/dist/types/src/apis/JmapMail/api.d.ts.map +1 -1
- package/dist/types/src/apis/JmapMail/index.d.ts +3 -3
- package/dist/types/src/apis/JmapMail/index.d.ts.map +1 -1
- package/dist/types/src/apis/JmapMail/query.d.ts +2 -2
- package/dist/types/src/apis/JmapMail/query.d.ts.map +1 -1
- package/dist/types/src/apis/index.d.ts +2 -2
- package/dist/types/src/apis/index.d.ts.map +1 -1
- package/dist/types/src/capabilities/credential-form.d.ts.map +1 -1
- package/dist/types/src/capabilities/gen/browser.d.ts +6 -0
- package/dist/types/src/capabilities/gen/browser.d.ts.map +1 -0
- package/dist/types/src/capabilities/gen/tauri.d.ts +6 -0
- package/dist/types/src/capabilities/gen/tauri.d.ts.map +1 -0
- package/dist/types/src/errors.d.ts +30 -0
- package/dist/types/src/errors.d.ts.map +1 -1
- package/dist/types/src/index.d.ts +2 -4
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/operations/JmapOperationHandlerSet.d.ts.map +1 -1
- package/dist/types/src/operations/index.d.ts +1 -1
- package/dist/types/src/operations/index.d.ts.map +1 -1
- package/dist/types/src/operations/mail/send/handler.d.ts.map +1 -1
- package/dist/types/src/operations/mail/send/index.d.ts +1 -1
- package/dist/types/src/operations/mail/send/index.d.ts.map +1 -1
- package/dist/types/src/operations/mail/sync/index.d.ts +2 -2
- package/dist/types/src/operations/mail/sync/index.d.ts.map +1 -1
- package/dist/types/src/operations/mail/sync/sync-provider.d.ts +2 -2
- package/dist/types/src/operations/mail/sync/sync-provider.d.ts.map +1 -1
- package/dist/types/src/services/index.d.ts +2 -2
- package/dist/types/src/services/index.d.ts.map +1 -1
- package/dist/types/src/services/jmap-mail-api.d.ts +3 -3
- package/dist/types/src/services/jmap-mail-api.d.ts.map +1 -1
- package/dist/types/src/testing/index.d.ts +2 -2
- package/dist/types/src/testing/index.d.ts.map +1 -1
- package/dist/types/src/testing/node.d.ts +1 -1
- package/dist/types/src/testing/node.d.ts.map +1 -1
- package/dist/types/src/testing/sync-fixture.d.ts +5 -5
- package/dist/types/src/testing/sync-fixture.d.ts.map +1 -1
- package/dist/types/src/types/index.d.ts +1 -1
- package/dist/types/src/types/index.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +31 -29
- package/src/JmapPlugin.workerd.test.ts +19 -0
- package/src/apis/Jmap/api.ts +6 -6
- package/src/apis/Jmap/index.ts +2 -2
- package/src/apis/JmapMail/api.ts +6 -6
- package/src/apis/JmapMail/index.ts +3 -3
- package/src/apis/JmapMail/query.test.ts +3 -3
- package/src/apis/JmapMail/query.ts +2 -2
- package/src/apis/index.ts +2 -2
- package/src/apis/jmap-api.test.ts +2 -2
- package/src/capabilities/connector.ts +6 -6
- package/src/capabilities/credential-form.test.ts +2 -2
- package/src/capabilities/credential-form.ts +9 -7
- package/src/capabilities/gen/browser.ts +32 -0
- package/src/capabilities/gen/node.ts +3 -3
- package/src/capabilities/gen/tauri.ts +32 -0
- package/src/capabilities/gen/workerd.ts +3 -3
- package/src/capabilities/index.ts +3 -3
- package/src/capabilities/mail-send.ts +1 -1
- package/src/errors.ts +6 -0
- package/src/index.ts +2 -4
- package/src/meta.ts +1 -1
- package/src/operations/JmapOperationHandlerSet.ts +5 -3
- package/src/operations/index.ts +1 -1
- package/src/operations/mail/mapper.ts +1 -1
- package/src/operations/mail/materialize/handler.ts +2 -2
- package/src/operations/mail/send/handler.ts +4 -3
- package/src/operations/mail/send/index.ts +1 -1
- package/src/operations/mail/sync/handler.ts +4 -4
- package/src/operations/mail/sync/index.ts +2 -2
- package/src/operations/mail/sync/mapper.test.ts +2 -2
- package/src/operations/mail/sync/sync-e2e.test.ts +2 -2
- package/src/operations/mail/sync/sync-provider.ts +13 -13
- package/src/operations/mail/sync/sync.test.ts +14 -14
- package/src/operations/mail/tags.ts +1 -1
- package/src/services/index.ts +2 -2
- package/src/services/jmap-mail-api.ts +3 -3
- package/src/testing/index.ts +2 -2
- package/src/testing/jmap-fixtures.test.ts +2 -2
- package/src/testing/node.ts +1 -1
- package/src/testing/sync-fixture.ts +7 -7
- package/src/types/index.ts +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"JmapOperationHandlerSet.mjs","names":[],"sources":["../../src/operations/JmapOperationHandlerSet.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Operation from '@dxos/compute/Operation';\nimport * as OperationHandlerSet from '@dxos/compute/OperationHandlerSet';\n\nimport { JmapOperation } from '#types';\n\nexport const handlers = OperationHandlerSet.lazy([\n JmapOperation.MaterializeJmapTarget.pipe(Operation.lazyHandler(() => import('./mail/materialize/handler'))),\n JmapOperation.JmapSend.pipe(Operation.lazyHandler(() => import('./mail/send'))),\n JmapOperation.JmapSync.pipe(Operation.lazyHandler(() => import('./mail/sync'))),\n]);\n"],"mappings":";;;;;;
|
|
1
|
+
{"version":3,"file":"JmapOperationHandlerSet.mjs","names":[],"sources":["../../src/operations/JmapOperationHandlerSet.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\n// @import-as-namespace\n\nimport * as Operation from '@dxos/compute/Operation';\nimport * as OperationHandlerSet from '@dxos/compute/OperationHandlerSet';\n\nimport { JmapOperation } from '#types';\n\nexport const handlers = OperationHandlerSet.lazy([\n JmapOperation.MaterializeJmapTarget.pipe(Operation.lazyHandler(() => import('./mail/materialize/handler.ts'))),\n JmapOperation.JmapSend.pipe(Operation.lazyHandler(() => import('./mail/send/index.ts'))),\n JmapOperation.JmapSync.pipe(Operation.lazyHandler(() => import('./mail/sync/index.ts'))),\n]);\n"],"mappings":";;;;;;AAWA,IAAa,WAAW,oBAAoB,KAAK;CAC/C,cAAc,sBAAsB,KAAK,UAAU,kBAAkB,OAAO,sBAAgC,CAAC;CAC7G,cAAc,SAAS,KAAK,UAAU,kBAAkB,OAAO,mBAAuB,CAAC;CACvF,cAAc,SAAS,KAAK,UAAU,kBAAkB,OAAO,mBAAuB,CAAC;AACzF,CAAC"}
|
package/dist/lib/apis.mjs
CHANGED
|
@@ -3,10 +3,10 @@ import { t as JmapApiError } from "./chunk-errors.mjs";
|
|
|
3
3
|
import { t as JmapCredentials } from "./chunk-jmap-credentials.mjs";
|
|
4
4
|
import * as Schema from "effect/Schema";
|
|
5
5
|
import * as Effect from "effect/Effect";
|
|
6
|
+
import * as HttpClient from "effect/http/HttpClient";
|
|
7
|
+
import * as HttpClientRequest from "effect/http/HttpClientRequest";
|
|
8
|
+
import * as HttpClientResponse from "effect/http/HttpClientResponse";
|
|
6
9
|
import * as Schedule from "effect/Schedule";
|
|
7
|
-
import * as HttpClient from "effect/unstable/http/HttpClient";
|
|
8
|
-
import * as HttpClientRequest from "effect/unstable/http/HttpClientRequest";
|
|
9
|
-
import * as HttpClientResponse from "effect/unstable/http/HttpClientResponse";
|
|
10
10
|
import { withAuthorization } from "@dxos/compute-runtime";
|
|
11
11
|
import { subDays, subMonths, subWeeks, subYears } from "date-fns";
|
|
12
12
|
import * as Match from "effect/Match";
|
package/dist/lib/apis.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"apis.mjs","names":[],"sources":["../../src/apis/Jmap/types.ts","../../src/apis/Jmap/api.ts","../../src/apis/Jmap/index.ts","../../src/apis/JmapMail/types.ts","../../src/apis/JmapMail/api.ts","../../src/apis/JmapMail/query.ts","../../src/apis/JmapMail/index.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Schema from 'effect/Schema';\n\n//\n// Shared JMAP core schemas (RFC 8620). These are capability-agnostic — they apply to mail, calendars,\n// and contacts alike.\n//\n\n/** Session object returned from `https://${host}/.well-known/jmap` (RFC 8620 §2). */\nexport const Session = Schema.Struct({\n /** Endpoint for all subsequent API requests. */\n apiUrl: Schema.String,\n /**\n * URI Template (RFC 6570) for blob downloads, with `accountId`/`blobId`/`type`/`name` variables\n * (RFC 8620 §6.2). Required, matching the spec — every real JMAP session advertises one.\n */\n downloadUrl: Schema.String,\n /** Authenticated username (used to seed the connection account when the form leaves it blank). */\n username: Schema.optional(Schema.String),\n /** Capability urn → primary account id (e.g. `urn:ietf:params:jmap:mail`). */\n primaryAccounts: Schema.Record(Schema.String, Schema.String),\n accounts: Schema.optional(Schema.Record(Schema.String, Schema.Unknown)),\n capabilities: Schema.optional(Schema.Record(Schema.String, Schema.Unknown)),\n state: Schema.optional(Schema.String),\n});\nexport type Session = Schema.Schema.Type<typeof Session>;\n\n/** A method-level error response: `[\"error\", { type, description }, callId]` (RFC 8620 §3.6.1). */\nexport const MethodError = Schema.Struct({\n type: Schema.String,\n description: Schema.optional(Schema.NullOr(Schema.String)),\n});\nexport type MethodError = Schema.Schema.Type<typeof MethodError>;\n\n/** A single `[name, args, callId]` invocation result; `args` is decoded per-method by the caller. */\nexport const MethodResponse = Schema.Tuple([Schema.String, Schema.Unknown, Schema.String]);\nexport type MethodResponse = Schema.Schema.Type<typeof MethodResponse>;\n\n/** The top-level response envelope of a batched API request (RFC 8620 §3.3). */\nexport const Response = Schema.Struct({\n methodResponses: Schema.Array(MethodResponse),\n sessionState: Schema.optional(Schema.String),\n});\nexport type Response = Schema.Schema.Type<typeof Response>;\n\n//\n// `Email/query` filter (RFC 8621 §4.4.1). Constructed client-side (never decoded), so these are plain\n// types rather than Schemas. Shared here because future calendar/contacts filters share the same\n// AND/OR/NOT operator structure (RFC 8620 §5.5).\n//\n\n/** A single filter condition; all present properties must match. */\nexport type FilterCondition = {\n readonly inMailbox?: string;\n readonly inMailboxOtherThan?: readonly string[];\n readonly before?: string;\n readonly after?: string;\n readonly minSize?: number;\n readonly maxSize?: number;\n readonly hasKeyword?: string;\n readonly notKeyword?: string;\n readonly allInThreadHaveKeyword?: string;\n readonly someInThreadHaveKeyword?: string;\n readonly noneInThreadHaveKeyword?: string;\n readonly text?: string;\n readonly from?: string;\n readonly to?: string;\n readonly cc?: string;\n readonly bcc?: string;\n readonly subject?: string;\n readonly body?: string;\n readonly header?: readonly string[];\n readonly hasAttachment?: boolean;\n};\n\n/** Combines sub-filters (RFC 8620 §5.5). */\nexport type FilterOperator = {\n readonly operator: 'AND' | 'OR' | 'NOT';\n readonly conditions: readonly Filter[];\n};\n\n/** An `Email/query` filter: a single condition or an AND/OR/NOT combination. */\nexport type Filter = FilterCondition | FilterOperator;\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Effect from 'effect/Effect';\nimport * as Schedule from 'effect/Schedule';\nimport * as Schema from 'effect/Schema';\nimport * as HttpClient from 'effect/unstable/http/HttpClient';\nimport * as HttpClientRequest from 'effect/unstable/http/HttpClientRequest';\nimport * as HttpClientResponse from 'effect/unstable/http/HttpClientResponse';\n\nimport { withAuthorization } from '@dxos/compute-runtime';\n\nimport { JmapApiError } from '../../errors';\nimport { JmapCredentials } from '../../services/jmap-credentials';\nimport { MethodError, Response, Session } from './types';\n\n/** Shared per-attempt timeout/retry policy for JMAP HTTP requests (session, batched API, blob download). */\nexport const REQUEST_TIMEOUT = '10 seconds';\nexport const REQUEST_RETRY = Schedule.exponential(1_000).pipe(Schedule.upTo({ times: 3 }));\n\n// Retry transient failures (network, 5xx, timeout) but not 4xx — a bad host/token or malformed\n// request will fail identically on retry, so retrying only adds latency.\nexport const shouldRetry = (error: unknown): boolean =>\n !(error instanceof JmapApiError && error.status !== undefined && error.status >= 400 && error.status < 500);\n\n/** Capability set for read/write mail requests. */\nexport const MAIL_CAPABILITIES = ['urn:ietf:params:jmap:core', 'urn:ietf:params:jmap:mail'] as const;\n/** Capability set including submission, required to send mail. */\nexport const SUBMISSION_CAPABILITIES = [...MAIL_CAPABILITIES, 'urn:ietf:params:jmap:submission'] as const;\n\n/** A single `[methodName, args, callId]` invocation in a batched request. */\nexport type MethodCall = readonly [string, unknown, string];\n\n/** A batched JMAP API request body (RFC 8620 §3.3). */\nexport type RequestBody = {\n readonly using: readonly string[];\n readonly methodCalls: readonly MethodCall[];\n};\n\n/**\n * Discovers the JMAP session: `GET https://${host}/.well-known/jmap` (the well-known URL\n * 302-redirects to the session resource, which `fetch` follows). Yields `apiUrl` +\n * `primaryAccounts`. Tracer disabled (Effect + CORS: https://github.com/Effect-TS/effect/issues/4568).\n */\nexport const getSession: Effect.Effect<Session, JmapApiError, HttpClient.HttpClient | JmapCredentials> = Effect.gen(\n function* () {\n const { host, token } = yield* JmapCredentials;\n const httpClient = yield* HttpClient.HttpClient.pipe(Effect.map(withAuthorization(token, 'Bearer')));\n const httpClientWithTracerDisabled = httpClient.pipe(\n HttpClient.transformResponse(Effect.provideService(HttpClient.TracerDisabledWhen, () => true)),\n );\n\n return yield* HttpClientRequest.get(`https://${host}/.well-known/jmap`).pipe(\n HttpClientRequest.setHeader('accept', 'application/json'),\n httpClientWithTracerDisabled.execute,\n Effect.flatMap(decodeJsonOrFail(Session)),\n Effect.timeout(REQUEST_TIMEOUT),\n Effect.retry({ schedule: REQUEST_RETRY, while: shouldRetry }),\n Effect.scoped,\n Effect.withSpan('JmapGetSession'),\n Effect.mapError(asJmapApiError),\n );\n },\n);\n\n/**\n * Issues a batched JMAP API request (single POST to the session `apiUrl`) and decodes the response\n * envelope. Read requests retry on transient failure; pass `{ retry: false }` for non-idempotent\n * writes (draft create + submission) so a retry can't double-send.\n */\nexport const jmapRequest = (\n apiUrl: string,\n body: RequestBody,\n options: { retry?: boolean } = {},\n): Effect.Effect<Response, JmapApiError, HttpClient.HttpClient | JmapCredentials> =>\n Effect.gen(function* () {\n const { token } = yield* JmapCredentials;\n const httpClient = yield* HttpClient.HttpClient.pipe(Effect.map(withAuthorization(token, 'Bearer')));\n const httpClientWithTracerDisabled = httpClient.pipe(\n HttpClient.transformResponse(Effect.provideService(HttpClient.TracerDisabledWhen, () => true)),\n );\n\n const executed = HttpClientRequest.post(apiUrl).pipe(\n HttpClientRequest.setHeader('accept', 'application/json'),\n HttpClientRequest.bodyJsonUnsafe(body),\n httpClientWithTracerDisabled.execute,\n Effect.flatMap(decodeJsonOrFail(Response)),\n Effect.timeout(REQUEST_TIMEOUT),\n );\n\n return yield* (\n options.retry === false ? executed : executed.pipe(Effect.retry({ schedule: REQUEST_RETRY, while: shouldRetry }))\n ).pipe(Effect.scoped, Effect.withSpan('JmapApiRequest'), Effect.mapError(asJmapApiError));\n });\n\n/**\n * Extracts and decodes the result for a given `callId` from a response envelope. A method-level\n * `[\"error\", …]` response (or a decode failure) becomes a typed {@link JmapApiError}.\n */\nexport const getMethodResponse = <A, I, R>(\n response: Response,\n callId: string,\n schema: Schema.Codec<A, I, R>,\n): Effect.Effect<A, JmapApiError, R> => {\n const entry = response.methodResponses.find((methodResponse) => methodResponse[2] === callId);\n if (!entry) {\n return Effect.fail(new JmapApiError(undefined, `No method response for call ${callId}.`));\n }\n\n const [name, args] = entry;\n if (name === 'error') {\n return Schema.decodeUnknownEffect(MethodError)(args).pipe(\n Effect.matchEffect({\n onFailure: () => Effect.fail(new JmapApiError(undefined, `JMAP method error (${callId}).`)),\n onSuccess: (error) => Effect.fail(new JmapApiError(undefined, error.description ?? error.type, error.type)),\n }),\n );\n }\n\n return Schema.decodeUnknownEffect(schema)(args).pipe(Effect.mapError(asJmapApiError));\n};\n\n/** Decodes a 2xx JSON body against `schema`; a >=400 status fails with the (truncated) body text. */\nconst decodeJsonOrFail =\n <A, I, R>(schema: Schema.Codec<A, I, R>) =>\n (response: HttpClientResponse.HttpClientResponse): Effect.Effect<A, JmapApiError, R> =>\n Effect.gen(function* () {\n if (response.status >= 400) {\n const body = yield* response.text;\n return yield* Effect.fail(new JmapApiError(response.status, truncate(body)));\n }\n return yield* HttpClientResponse.schemaBodyJson(schema)(response);\n }).pipe(Effect.mapError(asJmapApiError));\n\n/** Collapses transport/decode failures (HttpClientError, ParseError, timeout) into a typed JmapApiError. */\nconst asJmapApiError = (error: unknown): JmapApiError =>\n error instanceof JmapApiError\n ? error\n : new JmapApiError(undefined, error instanceof Error ? error.message : String(error));\n\nconst truncate = (text: string, max = 500): string => (text.length > max ? `${text.slice(0, max)}…` : text);\n","//\n// Copyright 2026 DXOS.org\n//\n\nexport * from './api';\nexport * from './types';\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Schema from 'effect/Schema';\n\n/** Structured email address — JMAP gives `{ name, email }` directly (no header parsing). */\nexport const EmailAddress = Schema.Struct({\n name: Schema.optional(Schema.NullOr(Schema.String)),\n email: Schema.String,\n});\nexport type EmailAddress = Schema.Schema.Type<typeof EmailAddress>;\n\n/** A folder. `role` is a well-known role (`inbox`, `drafts`, `sent`, `trash`, …) or null for custom folders. */\nexport const Mailbox = Schema.Struct({\n id: Schema.String,\n name: Schema.String,\n role: Schema.optional(Schema.NullOr(Schema.String)),\n parentId: Schema.optional(Schema.NullOr(Schema.String)),\n sortOrder: Schema.optional(Schema.Number),\n totalEmails: Schema.optional(Schema.Number),\n unreadEmails: Schema.optional(Schema.Number),\n});\nexport type Mailbox = Schema.Schema.Type<typeof Mailbox>;\n\n/** A decoded body part value (when fetched with `fetchTextBodyValues`). */\nexport const BodyValue = Schema.Struct({\n value: Schema.String,\n isEncodingProblem: Schema.optional(Schema.Boolean),\n isTruncated: Schema.optional(Schema.Boolean),\n});\nexport type BodyValue = Schema.Schema.Type<typeof BodyValue>;\n\n/** A body part reference (the `partId` keys into `Email.bodyValues`; `blobId` fetches raw bytes). */\nexport const EmailBodyPart = Schema.Struct({\n partId: Schema.optional(Schema.NullOr(Schema.String)),\n blobId: Schema.optional(Schema.NullOr(Schema.String)),\n size: Schema.optional(Schema.Number),\n type: Schema.optional(Schema.String),\n charset: Schema.optional(Schema.NullOr(Schema.String)),\n /** Attachment filename, present on parts listed in `Email.attachments`. */\n name: Schema.optional(Schema.NullOr(Schema.String)),\n /** MIME `Content-Disposition` (`attachment` or `inline`), present on parts listed in `Email.attachments`. */\n disposition: Schema.optional(Schema.NullOr(Schema.String)),\n /** The part's `Content-ID` header (RFC 8621 §4.1.4), if any — matches a `cid:` reference in an HTML body. */\n cid: Schema.optional(Schema.NullOr(Schema.String)),\n});\nexport type EmailBodyPart = Schema.Schema.Type<typeof EmailBodyPart>;\n\n/** An email (RFC 8621 §4). Only the properties requested in `Email/get` are present. */\nexport const Email = Schema.Struct({\n id: Schema.String,\n blobId: Schema.optional(Schema.String),\n // Server-set and always present on a fetched Email (RFC 8621 §4.1.1); `EMAIL_PROPERTIES` requests it.\n threadId: Schema.String,\n mailboxIds: Schema.optional(Schema.Record(Schema.String, Schema.Boolean)),\n keywords: Schema.optional(Schema.Record(Schema.String, Schema.Boolean)),\n from: Schema.optional(Schema.NullOr(Schema.Array(EmailAddress))),\n to: Schema.optional(Schema.NullOr(Schema.Array(EmailAddress))),\n cc: Schema.optional(Schema.NullOr(Schema.Array(EmailAddress))),\n bcc: Schema.optional(Schema.NullOr(Schema.Array(EmailAddress))),\n subject: Schema.optional(Schema.NullOr(Schema.String)),\n receivedAt: Schema.String,\n sentAt: Schema.optional(Schema.NullOr(Schema.String)),\n preview: Schema.optional(Schema.NullOr(Schema.String)),\n messageId: Schema.optional(Schema.NullOr(Schema.Array(Schema.String))),\n inReplyTo: Schema.optional(Schema.NullOr(Schema.Array(Schema.String))),\n references: Schema.optional(Schema.NullOr(Schema.Array(Schema.String))),\n bodyValues: Schema.optional(Schema.Record(Schema.String, BodyValue)),\n textBody: Schema.optional(Schema.Array(EmailBodyPart)),\n htmlBody: Schema.optional(Schema.Array(EmailBodyPart)),\n /** Non-body parts (RFC 8621 §4.1.4) — the attachments proper, distinct from `textBody`/`htmlBody`. */\n attachments: Schema.optional(Schema.Array(EmailBodyPart)),\n});\nexport type Email = Schema.Schema.Type<typeof Email>;\n\n/** A sending identity (RFC 8621 §6); `email` is an address the server permits as `from`. */\nexport const Identity = Schema.Struct({\n id: Schema.String,\n name: Schema.optional(Schema.NullOr(Schema.String)),\n email: Schema.String,\n});\nexport type Identity = Schema.Schema.Type<typeof Identity>;\n\n//\n// Method-result schemas.\n//\n\nexport const MailboxGetResult = Schema.Struct({\n accountId: Schema.optional(Schema.String),\n state: Schema.optional(Schema.String),\n list: Schema.Array(Mailbox),\n notFound: Schema.optional(Schema.NullOr(Schema.Array(Schema.String))),\n});\nexport type MailboxGetResult = Schema.Schema.Type<typeof MailboxGetResult>;\n\nexport const EmailQueryResult = Schema.Struct({\n accountId: Schema.optional(Schema.String),\n queryState: Schema.optional(Schema.String),\n position: Schema.optional(Schema.Number),\n total: Schema.optional(Schema.Number),\n limit: Schema.optional(Schema.Number),\n ids: Schema.Array(Schema.String),\n});\nexport type EmailQueryResult = Schema.Schema.Type<typeof EmailQueryResult>;\n\nexport const EmailGetResult = Schema.Struct({\n accountId: Schema.optional(Schema.String),\n state: Schema.optional(Schema.String),\n list: Schema.Array(Email),\n notFound: Schema.optional(Schema.NullOr(Schema.Array(Schema.String))),\n});\nexport type EmailGetResult = Schema.Schema.Type<typeof EmailGetResult>;\n\n/** `Email/changes` delta since an opaque `sinceState` token (RFC 8621 §4.3 / RFC 8620 §5.2). */\nexport const EmailChangesResult = Schema.Struct({\n accountId: Schema.optional(Schema.String),\n oldState: Schema.String,\n newState: Schema.String,\n hasMoreChanges: Schema.Boolean,\n created: Schema.Array(Schema.String),\n updated: Schema.Array(Schema.String),\n destroyed: Schema.Array(Schema.String),\n});\nexport type EmailChangesResult = Schema.Schema.Type<typeof EmailChangesResult>;\n\nexport const IdentityGetResult = Schema.Struct({\n accountId: Schema.optional(Schema.String),\n state: Schema.optional(Schema.String),\n list: Schema.Array(Identity),\n notFound: Schema.optional(Schema.NullOr(Schema.Array(Schema.String))),\n});\nexport type IdentityGetResult = Schema.Schema.Type<typeof IdentityGetResult>;\n\nexport const EmailSetResult = Schema.Struct({\n accountId: Schema.optional(Schema.String),\n oldState: Schema.optional(Schema.NullOr(Schema.String)),\n newState: Schema.optional(Schema.String),\n created: Schema.optional(\n Schema.NullOr(\n Schema.Record(\n Schema.String,\n Schema.Struct({\n id: Schema.String,\n blobId: Schema.optional(Schema.String),\n threadId: Schema.optional(Schema.String),\n size: Schema.optional(Schema.Number),\n }),\n ),\n ),\n ),\n updated: Schema.optional(Schema.NullOr(Schema.Record(Schema.String, Schema.Unknown))),\n destroyed: Schema.optional(Schema.NullOr(Schema.Array(Schema.String))),\n notCreated: Schema.optional(\n Schema.NullOr(\n Schema.Record(\n Schema.String,\n Schema.Struct({ type: Schema.String, description: Schema.optional(Schema.NullOr(Schema.String)) }),\n ),\n ),\n ),\n notUpdated: Schema.optional(\n Schema.NullOr(\n Schema.Record(\n Schema.String,\n Schema.Struct({ type: Schema.String, description: Schema.optional(Schema.NullOr(Schema.String)) }),\n ),\n ),\n ),\n notDestroyed: Schema.optional(\n Schema.NullOr(\n Schema.Record(\n Schema.String,\n Schema.Struct({ type: Schema.String, description: Schema.optional(Schema.NullOr(Schema.String)) }),\n ),\n ),\n ),\n});\nexport type EmailSetResult = Schema.Schema.Type<typeof EmailSetResult>;\n\nexport const EmailSubmissionSetResult = Schema.Struct({\n accountId: Schema.optional(Schema.String),\n newState: Schema.optional(Schema.String),\n created: Schema.optional(Schema.NullOr(Schema.Record(Schema.String, Schema.Struct({ id: Schema.String })))),\n notCreated: Schema.optional(\n Schema.NullOr(\n Schema.Record(\n Schema.String,\n Schema.Struct({ type: Schema.String, description: Schema.optional(Schema.NullOr(Schema.String)) }),\n ),\n ),\n ),\n});\nexport type EmailSubmissionSetResult = Schema.Schema.Type<typeof EmailSubmissionSetResult>;\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Effect from 'effect/Effect';\nimport * as HttpClient from 'effect/unstable/http/HttpClient';\nimport * as HttpClientRequest from 'effect/unstable/http/HttpClientRequest';\n\nimport { withAuthorization } from '@dxos/compute-runtime';\n\nimport { JmapApiError } from '../../errors';\nimport { JmapCredentials } from '../../services/jmap-credentials';\nimport {\n MAIL_CAPABILITIES,\n REQUEST_RETRY,\n REQUEST_TIMEOUT,\n SUBMISSION_CAPABILITIES,\n getMethodResponse,\n jmapRequest,\n shouldRetry,\n} from '../Jmap/api';\nimport {\n type EmailAddress,\n EmailChangesResult,\n EmailGetResult,\n EmailQueryResult,\n EmailSetResult,\n EmailSubmissionSetResult,\n IdentityGetResult,\n MailboxGetResult,\n} from './types';\n\n/**\n * Resolved per-request context: the session `apiUrl`, the mail account id, and (optionally) the\n * session's blob `downloadUrl` template (RFC 8620 §6.2). Most operations (mailboxGet, emailQuery,\n * send, delete, …) don't need it and construct a `Target` without it; only the attachment-fetching\n * path populates it from `Jmap.Session.downloadUrl`, so {@link downloadBlob} is the sole consumer\n * that requires it — absent here just means \"this call site never populated it\", not \"the server\n * didn't advertise one\" (every real session does).\n */\nexport type Target = {\n readonly apiUrl: string;\n readonly accountId: string;\n readonly downloadUrl?: string;\n};\n\n/** Expands a JMAP `downloadUrl` URI Template (RFC 6570 level 1) with the given variables. */\nconst expandDownloadUrl = (\n template: string,\n variables: { accountId: string; blobId: string; type: string; name: string },\n): string =>\n template.replace(/\\{(\\w+)\\}/g, (_, key: string) =>\n key in variables ? encodeURIComponent(variables[key as keyof typeof variables]) : '',\n );\n\n/**\n * Downloads a blob's raw bytes via the session's `downloadUrl` template. `name`/`type` are advisory\n * (they only affect the response's `Content-Disposition`/`Accept`), not required for correctness.\n */\nexport const downloadBlob = Effect.fn('downloadBlob')(function* (\n target: Target,\n blobId: string,\n options: { name?: string; type?: string } = {},\n) {\n if (!target.downloadUrl) {\n return yield* Effect.fail(new JmapApiError(undefined, 'Session has no downloadUrl.'));\n }\n const url = expandDownloadUrl(target.downloadUrl, {\n accountId: target.accountId,\n blobId,\n name: options.name ?? blobId,\n type: options.type ?? 'application/octet-stream',\n });\n\n const { token } = yield* JmapCredentials;\n const httpClient = yield* HttpClient.HttpClient.pipe(Effect.map(withAuthorization(token, 'Bearer')));\n\n // Mapped to `JmapApiError` before `Effect.timeout`/`Effect.retry` so `shouldRetry` can actually\n // distinguish a permanent 4xx from a transient failure — mirrors `jmapRequest`.\n const buffer = yield* HttpClientRequest.get(url).pipe(\n httpClient.execute,\n Effect.flatMap((response) => response.arrayBuffer),\n Effect.mapError(asJmapDownloadError),\n Effect.timeout(REQUEST_TIMEOUT),\n Effect.retry({ schedule: REQUEST_RETRY, while: shouldRetry }),\n Effect.scoped,\n Effect.mapError(asJmapDownloadError),\n );\n return new Uint8Array(buffer);\n});\n\n/** Collapses transport/decode failures into a typed {@link JmapApiError} (mirrors `Jmap/api.ts`). */\nconst asJmapDownloadError = (error: unknown): JmapApiError =>\n error instanceof JmapApiError\n ? error\n : new JmapApiError(undefined, error instanceof Error ? error.message : String(error));\n\n/** Email properties fetched by {@link emailGet} — enough for the mapper to build a Message. */\nexport const EMAIL_PROPERTIES = [\n 'id',\n 'blobId',\n 'threadId',\n 'mailboxIds',\n 'keywords',\n 'from',\n 'to',\n 'cc',\n 'subject',\n 'receivedAt',\n 'sentAt',\n 'preview',\n 'messageId',\n 'inReplyTo',\n 'references',\n 'bodyValues',\n 'textBody',\n 'htmlBody',\n 'attachments',\n] as const;\n\n/** Lists all folders (mailboxes) in the account (RFC 8621 §2.3). */\nexport const mailboxGet = Effect.fn('mailboxGet')(function* (target: Target) {\n const response = yield* jmapRequest(target.apiUrl, {\n using: MAIL_CAPABILITIES,\n methodCalls: [['Mailbox/get', { accountId: target.accountId, ids: null }, '0']],\n });\n return yield* getMethodResponse(response, '0', MailboxGetResult);\n});\n\n/** Queries email ids matching a filter (RFC 8621 §4.4). */\nexport const emailQuery = Effect.fn('emailQuery')(function* (\n target: Target,\n options: {\n filter?: unknown;\n sort?: readonly { property: string; isAscending?: boolean }[];\n position?: number;\n limit?: number;\n calculateTotal?: boolean;\n } = {},\n) {\n const args: Record<string, unknown> = { accountId: target.accountId };\n if (options.filter !== undefined) {\n args.filter = options.filter;\n }\n if (options.sort !== undefined) {\n args.sort = options.sort;\n }\n if (options.position !== undefined) {\n args.position = options.position;\n }\n if (options.limit !== undefined) {\n args.limit = options.limit;\n }\n if (options.calculateTotal !== undefined) {\n args.calculateTotal = options.calculateTotal;\n }\n\n const response = yield* jmapRequest(target.apiUrl, {\n using: MAIL_CAPABILITIES,\n methodCalls: [['Email/query', args, '0']],\n });\n return yield* getMethodResponse(response, '0', EmailQueryResult);\n});\n\n/** Fetches emails by id with decoded HTML and text body values (RFC 8621 §4.2). */\nexport const emailGet = Effect.fn('emailGet')(function* (\n target: Target,\n ids: readonly string[],\n properties: readonly string[] = EMAIL_PROPERTIES,\n) {\n const response = yield* jmapRequest(target.apiUrl, {\n using: MAIL_CAPABILITIES,\n methodCalls: [\n [\n 'Email/get',\n { accountId: target.accountId, ids, properties, fetchTextBodyValues: true, fetchHTMLBodyValues: true },\n '0',\n ],\n ],\n });\n return yield* getMethodResponse(response, '0', EmailGetResult);\n});\n\n/**\n * Fetches the delta of email changes since an opaque `sinceState` token (RFC 8621 §4.3). A server that\n * can't compute the delta (state too old / evicted) returns a `cannotCalculateChanges` method error,\n * surfaced as a {@link JmapApiError} with that `type` — the caller's cue to fall back to a full scan.\n * The token to pass comes from a prior `Email/get` `state` (NOT `Email/query` `queryState`).\n */\nexport const emailChanges = Effect.fn('emailChanges')(function* (\n target: Target,\n sinceState: string,\n maxChanges?: number,\n) {\n const args: Record<string, unknown> = { accountId: target.accountId, sinceState };\n if (maxChanges !== undefined) {\n args.maxChanges = maxChanges;\n }\n const response = yield* jmapRequest(target.apiUrl, {\n using: MAIL_CAPABILITIES,\n methodCalls: [['Email/changes', args, '0']],\n });\n return yield* getMethodResponse(response, '0', EmailChangesResult);\n});\n\n/** Lists the account's sending identities (RFC 8621 §6.2). */\nexport const identityGet = Effect.fn('identityGet')(function* (target: Target) {\n const response = yield* jmapRequest(target.apiUrl, {\n using: SUBMISSION_CAPABILITIES,\n methodCalls: [['Identity/get', { accountId: target.accountId, ids: null }, '0']],\n });\n return yield* getMethodResponse(response, '0', IdentityGetResult);\n});\n\n/** Patches a single email (e.g. replace `mailboxIds` to move to Trash). Idempotent, so retryable. */\nexport const emailSetUpdate = Effect.fn('emailSetUpdate')(function* (\n target: Target,\n emailId: string,\n patch: Record<string, unknown>,\n) {\n const response = yield* jmapRequest(target.apiUrl, {\n using: MAIL_CAPABILITIES,\n methodCalls: [['Email/set', { accountId: target.accountId, update: { [emailId]: patch } }, '0']],\n });\n const result = yield* getMethodResponse(response, '0', EmailSetResult);\n const error = result.notUpdated?.[emailId];\n if (error) {\n return yield* Effect.fail(new JmapApiError(undefined, error.description ?? error.type, error.type));\n }\n return result;\n});\n\n/**\n * Creates a draft and submits it for delivery in a single batched request. Not retried (a retry\n * could double-send). Returns the created email's id and thread id.\n */\nexport const submitEmail = Effect.fn('submitEmail')(function* (\n target: Target,\n args: {\n identityId: string;\n draftsMailboxId: string;\n sentMailboxId: string;\n draft: {\n from: readonly EmailAddress[];\n to: readonly EmailAddress[];\n cc?: readonly EmailAddress[];\n bcc?: readonly EmailAddress[];\n subject?: string;\n inReplyTo?: readonly string[];\n references?: readonly string[];\n text: string;\n };\n },\n) {\n const { identityId, draftsMailboxId, sentMailboxId, draft } = args;\n const draftCreate: Record<string, unknown> = {\n mailboxIds: { [draftsMailboxId]: true },\n keywords: { $draft: true, $seen: true },\n from: draft.from,\n to: draft.to,\n bodyValues: { body: { value: draft.text } },\n textBody: [{ partId: 'body', type: 'text/plain' }],\n };\n if (draft.cc && draft.cc.length > 0) {\n draftCreate.cc = draft.cc;\n }\n if (draft.bcc && draft.bcc.length > 0) {\n draftCreate.bcc = draft.bcc;\n }\n if (draft.subject !== undefined) {\n draftCreate.subject = draft.subject;\n }\n if (draft.inReplyTo && draft.inReplyTo.length > 0) {\n draftCreate.inReplyTo = draft.inReplyTo;\n }\n if (draft.references && draft.references.length > 0) {\n draftCreate.references = draft.references;\n }\n\n const response = yield* jmapRequest(\n target.apiUrl,\n {\n using: SUBMISSION_CAPABILITIES,\n methodCalls: [\n ['Email/set', { accountId: target.accountId, create: { draft: draftCreate } }, '0'],\n [\n 'EmailSubmission/set',\n {\n accountId: target.accountId,\n create: { sub: { emailId: '#draft', identityId } },\n onSuccessUpdateEmail: {\n '#sub': {\n [`mailboxIds/${draftsMailboxId}`]: null,\n [`mailboxIds/${sentMailboxId}`]: true,\n 'keywords/$draft': null,\n },\n },\n },\n '1',\n ],\n ],\n },\n { retry: false },\n );\n\n const setResult = yield* getMethodResponse(response, '0', EmailSetResult);\n const created = setResult.created?.draft;\n if (!created) {\n const error = setResult.notCreated?.draft;\n return yield* Effect.fail(\n new JmapApiError(undefined, error?.description ?? error?.type ?? 'Draft was not created.', error?.type),\n );\n }\n\n const submissionResult = yield* getMethodResponse(response, '1', EmailSubmissionSetResult);\n if (!submissionResult.created?.sub) {\n const error = submissionResult.notCreated?.sub;\n return yield* Effect.fail(\n new JmapApiError(undefined, error?.description ?? error?.type ?? 'Email submission failed.', error?.type),\n );\n }\n\n return { id: created.id, threadId: created.threadId };\n});\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport { subDays, subMonths, subWeeks, subYears } from 'date-fns';\nimport * as Match from 'effect/Match';\nimport * as Option from 'effect/Option';\n\nimport { type Filter, type FilterCondition, type FilterOperator } from '../Jmap';\nimport { type Mailbox } from './types';\n\n/** Context for {@link parseMailQuery}: a clock (for relative dates) and a label/folder resolver. */\nexport type ParseContext = {\n readonly now: Date;\n /** Resolves a `label:`/`in:` name or system role to a JMAP mailbox id. */\n readonly resolveMailbox: (nameOrRole: string) => Option.Option<string>;\n};\n\ntype Token =\n | { readonly _tag: 'or' }\n | { readonly _tag: 'term'; readonly negate: boolean; readonly op: Option.Option<string>; readonly value: string };\n\n/**\n * Translates a Gmail-like query string into a JMAP `Email/query` filter (RFC 8621 §4.4.1).\n *\n * Supported operators: `from:`/`to:`/`cc:`/`bcc:`/`subject:`/`body:`, `label:`/`in:` (resolved to a\n * mailbox id), `is:unread|read|starred|flagged|unstarred|draft|answered`, `has:attachment`,\n * `after:`/`before:` (`YYYY/MM/DD` or `YYYY-MM-DD`), `newer_than:`/`older_than:` (e.g. `7d`, `2w`,\n * `3m`, `1y`), `larger:`/`smaller:` (e.g. `10M`, `500k`), `list:`/`deliveredto:` (header match),\n * quoted phrases, `-` negation, `OR` groups, and bare words (full-text). Space-separated terms are\n * AND-ed. Returns `None` for an empty query, or one whose terms all fail to resolve (e.g. an unknown\n * label).\n */\nexport const parseMailQuery = (query: string, ctx: ParseContext): Option.Option<Filter> =>\n buildFilter(tokenize(query), ctx);\n\n/** Resolves a label/folder name (case-insensitive) or a system role/alias to a mailbox id. */\nexport const resolveMailboxByNameOrRole = (folders: readonly Mailbox[], nameOrRole: string): Option.Option<string> => {\n const lowered = nameOrRole.toLowerCase();\n const role = ROLE_ALIASES[lowered] ?? lowered;\n const match =\n folders.find((folder) => folder.role === role) ?? folders.find((folder) => folder.name.toLowerCase() === lowered);\n return Option.fromNullishOr(match?.id);\n};\n\n//\n// Tokenizer.\n//\n\n// A token is an optional `-`, optional `op:` prefix, then a `\"quoted\"` value or a non-space run.\nconst TOKEN_RE = /-?(?:[A-Za-z_]+:)?\"[^\"]*\"|\\S+/g;\n\nconst tokenize = (query: string): readonly Token[] => (query.match(TOKEN_RE) ?? []).map(parseToken);\n\nconst parseToken = (raw: string): Token => {\n if (raw === 'OR') {\n return { _tag: 'or' };\n }\n const negate = raw.startsWith('-');\n const rest = negate ? raw.slice(1) : raw;\n const colon = rest.indexOf(':');\n if (colon > 0 && /^[A-Za-z_]+$/.test(rest.slice(0, colon))) {\n return {\n _tag: 'term',\n negate,\n op: Option.some(rest.slice(0, colon).toLowerCase()),\n value: stripQuotes(rest.slice(colon + 1)),\n };\n }\n return { _tag: 'term', negate, op: Option.none(), value: stripQuotes(rest) };\n};\n\nconst stripQuotes = (value: string): string =>\n value.length >= 2 && value.startsWith('\"') && value.endsWith('\"') ? value.slice(1, -1) : value;\n\n//\n// Folding tokens into a filter tree. Space-separated terms AND together; an `OR` token merges the\n// next term with the previous operand. Terms that resolve to `None` (unknown label, empty value) are\n// dropped.\n//\n\nconst buildFilter = (tokens: readonly Token[], ctx: ParseContext): Option.Option<Filter> => {\n const { operands } = tokens.reduce<{ operands: readonly Filter[]; pendingOr: boolean }>(\n (state, token) => {\n if (token._tag === 'or') {\n return { ...state, pendingOr: state.operands.length > 0 };\n }\n const leaf = buildTerm(token, ctx);\n if (Option.isNone(leaf)) {\n // A dropped term (unknown label, empty value) consumes any pending OR: the next valid term\n // must not merge with the previous operand unless its own `or` token immediately precedes it.\n return { ...state, pendingOr: false };\n }\n const previous = state.pendingOr ? state.operands[state.operands.length - 1] : undefined;\n return previous !== undefined\n ? { operands: [...state.operands.slice(0, -1), mergeOr(previous, leaf.value)], pendingOr: false }\n : { operands: [...state.operands, leaf.value], pendingOr: false };\n },\n { operands: [], pendingOr: false },\n );\n\n return Match.value(operands.length).pipe(\n Match.when(0, () => Option.none<Filter>()),\n Match.when(1, () => Option.fromNullishOr(operands[0])),\n Match.orElse(() => Option.some<Filter>({ operator: 'AND', conditions: operands })),\n );\n};\n\nconst mergeOr = (previous: Filter, next: Filter): FilterOperator =>\n isOperator(previous) && previous.operator === 'OR'\n ? { operator: 'OR', conditions: [...previous.conditions, next] }\n : { operator: 'OR', conditions: [previous, next] };\n\nconst isOperator = (filter: Filter): filter is FilterOperator => 'operator' in filter;\n\n/** Whether a filter restricts the mailbox scope (`inMailbox`/`inMailboxOtherThan`), recursively. */\nexport const filterScopesMailbox = (filter: Filter): boolean =>\n isOperator(filter)\n ? filter.conditions.some(filterScopesMailbox)\n : filter.inMailbox !== undefined || filter.inMailboxOtherThan !== undefined;\n\nconst buildTerm = (token: Extract<Token, { _tag: 'term' }>, ctx: ParseContext): Option.Option<Filter> =>\n buildLeaf(token.op, token.value, ctx).pipe(Option.map((leaf) => (token.negate ? negate(leaf) : leaf)));\n\nconst negate = (filter: Filter): FilterOperator => ({ operator: 'NOT', conditions: [filter] });\n\n//\n// Leaf construction (operator → JMAP FilterCondition).\n//\n\nconst buildLeaf = (op: Option.Option<string>, value: string, ctx: ParseContext): Option.Option<Filter> =>\n op.pipe(\n Option.match({\n onNone: () => textLeaf(value),\n onSome: (operator) => buildOperatorLeaf(operator, value, ctx),\n }),\n );\n\nconst buildOperatorLeaf = (operator: string, value: string, ctx: ParseContext): Option.Option<Filter> =>\n Match.value(operator).pipe(\n Match.whenOr('from', 'to', 'cc', 'bcc', 'subject', 'body', (field) =>\n condLeaf(value, STRING_FIELD_LEAVES[field](value)),\n ),\n Match.whenOr('label', 'in', () => ctx.resolveMailbox(value).pipe(Option.map((id) => ({ inMailbox: id })))),\n Match.when('is', () => Option.fromNullishOr(IS_LEAVES[value.toLowerCase()])),\n Match.when('has', () =>\n value.toLowerCase() === 'attachment' ? Option.some<Filter>({ hasAttachment: true }) : Option.none<Filter>(),\n ),\n Match.whenOr('after', 'newer', () => dateLeaf(value, 'after')),\n Match.whenOr('before', 'older', () => dateLeaf(value, 'before')),\n Match.when('newer_than', () => relativeDateLeaf(value, ctx.now, 'after')),\n Match.when('older_than', () => relativeDateLeaf(value, ctx.now, 'before')),\n Match.when('larger', () => sizeLeaf(value, 'minSize')),\n Match.when('smaller', () => sizeLeaf(value, 'maxSize')),\n Match.when('list', () => headerLeaf('List-Id', value)),\n Match.when('deliveredto', () => headerLeaf('Delivered-To', value)),\n // Unknown operator: keep the literal `op:value` as a full-text term (mirrors Gmail's fallback).\n Match.orElse(() => textLeaf(`${operator}:${value}`)),\n );\n\ntype StringField = 'from' | 'to' | 'cc' | 'bcc' | 'subject' | 'body';\n\nconst STRING_FIELD_LEAVES: Record<StringField, (value: string) => FilterCondition> = {\n from: (value) => ({ from: value }),\n to: (value) => ({ to: value }),\n cc: (value) => ({ cc: value }),\n bcc: (value) => ({ bcc: value }),\n subject: (value) => ({ subject: value }),\n body: (value) => ({ body: value }),\n};\n\nconst IS_LEAVES: Record<string, Filter> = {\n unread: { notKeyword: '$seen' },\n read: { hasKeyword: '$seen' },\n starred: { hasKeyword: '$flagged' },\n flagged: { hasKeyword: '$flagged' },\n unstarred: { notKeyword: '$flagged' },\n unflagged: { notKeyword: '$flagged' },\n draft: { hasKeyword: '$draft' },\n answered: { hasKeyword: '$answered' },\n replied: { hasKeyword: '$answered' },\n};\n\nconst ROLE_ALIASES: Record<string, string> = { spam: 'junk', bin: 'trash', deleted: 'trash' };\n\nconst SIZE_UNITS: Record<string, number> = { '': 1, 'k': 1024, 'm': 1024 * 1024, 'g': 1024 * 1024 * 1024 };\nconst DATE_RE = /^(\\d{4})[/-](\\d{1,2})[/-](\\d{1,2})$/;\nconst RELATIVE_RE = /^(\\d+)([dwmy])$/;\nconst SIZE_RE = /^(\\d+)([kmg]?)b?$/i;\n\n/** Wraps a built condition in `Some`, or `None` when the value is blank. */\nconst condLeaf = (value: string, condition: Filter): Option.Option<Filter> =>\n value.trim().length === 0 ? Option.none() : Option.some(condition);\n\nconst textLeaf = (value: string): Option.Option<Filter> => condLeaf(value, { text: value });\n\nconst headerLeaf = (name: string, value: string): Option.Option<Filter> => condLeaf(value, { header: [name, value] });\n\nconst dateLeaf = (value: string, bound: 'after' | 'before'): Option.Option<Filter> => {\n const match = DATE_RE.exec(value);\n if (!match) {\n return Option.none();\n }\n const iso = new Date(Date.UTC(Number(match[1]), Number(match[2]) - 1, Number(match[3]))).toISOString();\n return Option.some(bound === 'after' ? { after: iso } : { before: iso });\n};\n\nconst relativeDateLeaf = (value: string, now: Date, bound: 'after' | 'before'): Option.Option<Filter> => {\n const match = RELATIVE_RE.exec(value.toLowerCase());\n if (!match) {\n return Option.none();\n }\n const amount = Number(match[1]);\n const date = Match.value(match[2]).pipe(\n Match.when('w', () => subWeeks(now, amount)),\n Match.when('m', () => subMonths(now, amount)),\n Match.when('y', () => subYears(now, amount)),\n Match.orElse(() => subDays(now, amount)),\n );\n const iso = date.toISOString();\n return Option.some(bound === 'after' ? { after: iso } : { before: iso });\n};\n\nconst sizeLeaf = (value: string, bound: 'minSize' | 'maxSize'): Option.Option<Filter> => {\n const match = SIZE_RE.exec(value.toLowerCase());\n if (!match) {\n return Option.none();\n }\n const bytes = Number(match[1]) * (SIZE_UNITS[match[2] ?? ''] ?? 1);\n return Option.some(bound === 'minSize' ? { minSize: bytes } : { maxSize: bytes });\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\nexport * from './api';\nexport * from './types';\nexport * from './query';\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"apis.mjs","names":[],"sources":["../../src/apis/Jmap/types.ts","../../src/apis/Jmap/api.ts","../../src/apis/Jmap/index.ts","../../src/apis/JmapMail/types.ts","../../src/apis/JmapMail/api.ts","../../src/apis/JmapMail/query.ts","../../src/apis/JmapMail/index.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Schema from 'effect/Schema';\n\n//\n// Shared JMAP core schemas (RFC 8620). These are capability-agnostic — they apply to mail, calendars,\n// and contacts alike.\n//\n\n/** Session object returned from `https://${host}/.well-known/jmap` (RFC 8620 §2). */\nexport const Session = Schema.Struct({\n /** Endpoint for all subsequent API requests. */\n apiUrl: Schema.String,\n /**\n * URI Template (RFC 6570) for blob downloads, with `accountId`/`blobId`/`type`/`name` variables\n * (RFC 8620 §6.2). Required, matching the spec — every real JMAP session advertises one.\n */\n downloadUrl: Schema.String,\n /** Authenticated username (used to seed the connection account when the form leaves it blank). */\n username: Schema.optional(Schema.String),\n /** Capability urn → primary account id (e.g. `urn:ietf:params:jmap:mail`). */\n primaryAccounts: Schema.Record(Schema.String, Schema.String),\n accounts: Schema.optional(Schema.Record(Schema.String, Schema.Unknown)),\n capabilities: Schema.optional(Schema.Record(Schema.String, Schema.Unknown)),\n state: Schema.optional(Schema.String),\n});\nexport type Session = Schema.Schema.Type<typeof Session>;\n\n/** A method-level error response: `[\"error\", { type, description }, callId]` (RFC 8620 §3.6.1). */\nexport const MethodError = Schema.Struct({\n type: Schema.String,\n description: Schema.optional(Schema.NullOr(Schema.String)),\n});\nexport type MethodError = Schema.Schema.Type<typeof MethodError>;\n\n/** A single `[name, args, callId]` invocation result; `args` is decoded per-method by the caller. */\nexport const MethodResponse = Schema.Tuple([Schema.String, Schema.Unknown, Schema.String]);\nexport type MethodResponse = Schema.Schema.Type<typeof MethodResponse>;\n\n/** The top-level response envelope of a batched API request (RFC 8620 §3.3). */\nexport const Response = Schema.Struct({\n methodResponses: Schema.Array(MethodResponse),\n sessionState: Schema.optional(Schema.String),\n});\nexport type Response = Schema.Schema.Type<typeof Response>;\n\n//\n// `Email/query` filter (RFC 8621 §4.4.1). Constructed client-side (never decoded), so these are plain\n// types rather than Schemas. Shared here because future calendar/contacts filters share the same\n// AND/OR/NOT operator structure (RFC 8620 §5.5).\n//\n\n/** A single filter condition; all present properties must match. */\nexport type FilterCondition = {\n readonly inMailbox?: string;\n readonly inMailboxOtherThan?: readonly string[];\n readonly before?: string;\n readonly after?: string;\n readonly minSize?: number;\n readonly maxSize?: number;\n readonly hasKeyword?: string;\n readonly notKeyword?: string;\n readonly allInThreadHaveKeyword?: string;\n readonly someInThreadHaveKeyword?: string;\n readonly noneInThreadHaveKeyword?: string;\n readonly text?: string;\n readonly from?: string;\n readonly to?: string;\n readonly cc?: string;\n readonly bcc?: string;\n readonly subject?: string;\n readonly body?: string;\n readonly header?: readonly string[];\n readonly hasAttachment?: boolean;\n};\n\n/** Combines sub-filters (RFC 8620 §5.5). */\nexport type FilterOperator = {\n readonly operator: 'AND' | 'OR' | 'NOT';\n readonly conditions: readonly Filter[];\n};\n\n/** An `Email/query` filter: a single condition or an AND/OR/NOT combination. */\nexport type Filter = FilterCondition | FilterOperator;\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Effect from 'effect/Effect';\nimport * as HttpClient from 'effect/http/HttpClient';\nimport * as HttpClientRequest from 'effect/http/HttpClientRequest';\nimport * as HttpClientResponse from 'effect/http/HttpClientResponse';\nimport * as Schedule from 'effect/Schedule';\nimport * as Schema from 'effect/Schema';\n\nimport { withAuthorization } from '@dxos/compute-runtime';\n\nimport { JmapApiError } from '../../errors.ts';\nimport { JmapCredentials } from '../../services/jmap-credentials.ts';\nimport { MethodError, Response, Session } from './types.ts';\n\n/** Shared per-attempt timeout/retry policy for JMAP HTTP requests (session, batched API, blob download). */\nexport const REQUEST_TIMEOUT = '10 seconds';\nexport const REQUEST_RETRY = Schedule.exponential(1_000).pipe(Schedule.upTo({ times: 3 }));\n\n// Retry transient failures (network, 5xx, timeout) but not 4xx — a bad host/token or malformed\n// request will fail identically on retry, so retrying only adds latency.\nexport const shouldRetry = (error: unknown): boolean =>\n !(error instanceof JmapApiError && error.status !== undefined && error.status >= 400 && error.status < 500);\n\n/** Capability set for read/write mail requests. */\nexport const MAIL_CAPABILITIES = ['urn:ietf:params:jmap:core', 'urn:ietf:params:jmap:mail'] as const;\n/** Capability set including submission, required to send mail. */\nexport const SUBMISSION_CAPABILITIES = [...MAIL_CAPABILITIES, 'urn:ietf:params:jmap:submission'] as const;\n\n/** A single `[methodName, args, callId]` invocation in a batched request. */\nexport type MethodCall = readonly [string, unknown, string];\n\n/** A batched JMAP API request body (RFC 8620 §3.3). */\nexport type RequestBody = {\n readonly using: readonly string[];\n readonly methodCalls: readonly MethodCall[];\n};\n\n/**\n * Discovers the JMAP session: `GET https://${host}/.well-known/jmap` (the well-known URL\n * 302-redirects to the session resource, which `fetch` follows). Yields `apiUrl` +\n * `primaryAccounts`. Tracer disabled (Effect + CORS: https://github.com/Effect-TS/effect/issues/4568).\n */\nexport const getSession: Effect.Effect<Session, JmapApiError, HttpClient.HttpClient | JmapCredentials> = Effect.gen(\n function* () {\n const { host, token } = yield* JmapCredentials;\n const httpClient = yield* HttpClient.HttpClient.pipe(Effect.map(withAuthorization(token, 'Bearer')));\n const httpClientWithTracerDisabled = httpClient.pipe(\n HttpClient.transformResponse(Effect.provideService(HttpClient.TracerDisabledWhen, () => true)),\n );\n\n return yield* HttpClientRequest.get(`https://${host}/.well-known/jmap`).pipe(\n HttpClientRequest.setHeader('accept', 'application/json'),\n httpClientWithTracerDisabled.execute,\n Effect.flatMap(decodeJsonOrFail(Session)),\n Effect.timeout(REQUEST_TIMEOUT),\n Effect.retry({ schedule: REQUEST_RETRY, while: shouldRetry }),\n Effect.scoped,\n Effect.withSpan('JmapGetSession'),\n Effect.mapError(asJmapApiError),\n );\n },\n);\n\n/**\n * Issues a batched JMAP API request (single POST to the session `apiUrl`) and decodes the response\n * envelope. Read requests retry on transient failure; pass `{ retry: false }` for non-idempotent\n * writes (draft create + submission) so a retry can't double-send.\n */\nexport const jmapRequest = (\n apiUrl: string,\n body: RequestBody,\n options: { retry?: boolean } = {},\n): Effect.Effect<Response, JmapApiError, HttpClient.HttpClient | JmapCredentials> =>\n Effect.gen(function* () {\n const { token } = yield* JmapCredentials;\n const httpClient = yield* HttpClient.HttpClient.pipe(Effect.map(withAuthorization(token, 'Bearer')));\n const httpClientWithTracerDisabled = httpClient.pipe(\n HttpClient.transformResponse(Effect.provideService(HttpClient.TracerDisabledWhen, () => true)),\n );\n\n const executed = HttpClientRequest.post(apiUrl).pipe(\n HttpClientRequest.setHeader('accept', 'application/json'),\n HttpClientRequest.bodyJsonUnsafe(body),\n httpClientWithTracerDisabled.execute,\n Effect.flatMap(decodeJsonOrFail(Response)),\n Effect.timeout(REQUEST_TIMEOUT),\n );\n\n return yield* (\n options.retry === false ? executed : executed.pipe(Effect.retry({ schedule: REQUEST_RETRY, while: shouldRetry }))\n ).pipe(Effect.scoped, Effect.withSpan('JmapApiRequest'), Effect.mapError(asJmapApiError));\n });\n\n/**\n * Extracts and decodes the result for a given `callId` from a response envelope. A method-level\n * `[\"error\", …]` response (or a decode failure) becomes a typed {@link JmapApiError}.\n */\nexport const getMethodResponse = <A, I, R>(\n response: Response,\n callId: string,\n schema: Schema.Codec<A, I, R>,\n): Effect.Effect<A, JmapApiError, R> => {\n const entry = response.methodResponses.find((methodResponse) => methodResponse[2] === callId);\n if (!entry) {\n return Effect.fail(new JmapApiError(undefined, `No method response for call ${callId}.`));\n }\n\n const [name, args] = entry;\n if (name === 'error') {\n return Schema.decodeUnknownEffect(MethodError)(args).pipe(\n Effect.matchEffect({\n onFailure: () => Effect.fail(new JmapApiError(undefined, `JMAP method error (${callId}).`)),\n onSuccess: (error) => Effect.fail(new JmapApiError(undefined, error.description ?? error.type, error.type)),\n }),\n );\n }\n\n return Schema.decodeUnknownEffect(schema)(args).pipe(Effect.mapError(asJmapApiError));\n};\n\n/** Decodes a 2xx JSON body against `schema`; a >=400 status fails with the (truncated) body text. */\nconst decodeJsonOrFail =\n <A, I, R>(schema: Schema.Codec<A, I, R>) =>\n (response: HttpClientResponse.HttpClientResponse): Effect.Effect<A, JmapApiError, R> =>\n Effect.gen(function* () {\n if (response.status >= 400) {\n const body = yield* response.text;\n return yield* Effect.fail(new JmapApiError(response.status, truncate(body)));\n }\n return yield* HttpClientResponse.schemaBodyJson(schema)(response);\n }).pipe(Effect.mapError(asJmapApiError));\n\n/** Collapses transport/decode failures (HttpClientError, ParseError, timeout) into a typed JmapApiError. */\nconst asJmapApiError = (error: unknown): JmapApiError =>\n error instanceof JmapApiError\n ? error\n : new JmapApiError(undefined, error instanceof Error ? error.message : String(error));\n\nconst truncate = (text: string, max = 500): string => (text.length > max ? `${text.slice(0, max)}…` : text);\n","//\n// Copyright 2026 DXOS.org\n//\n\nexport * from './api.ts';\nexport * from './types.ts';\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Schema from 'effect/Schema';\n\n/** Structured email address — JMAP gives `{ name, email }` directly (no header parsing). */\nexport const EmailAddress = Schema.Struct({\n name: Schema.optional(Schema.NullOr(Schema.String)),\n email: Schema.String,\n});\nexport type EmailAddress = Schema.Schema.Type<typeof EmailAddress>;\n\n/** A folder. `role` is a well-known role (`inbox`, `drafts`, `sent`, `trash`, …) or null for custom folders. */\nexport const Mailbox = Schema.Struct({\n id: Schema.String,\n name: Schema.String,\n role: Schema.optional(Schema.NullOr(Schema.String)),\n parentId: Schema.optional(Schema.NullOr(Schema.String)),\n sortOrder: Schema.optional(Schema.Number),\n totalEmails: Schema.optional(Schema.Number),\n unreadEmails: Schema.optional(Schema.Number),\n});\nexport type Mailbox = Schema.Schema.Type<typeof Mailbox>;\n\n/** A decoded body part value (when fetched with `fetchTextBodyValues`). */\nexport const BodyValue = Schema.Struct({\n value: Schema.String,\n isEncodingProblem: Schema.optional(Schema.Boolean),\n isTruncated: Schema.optional(Schema.Boolean),\n});\nexport type BodyValue = Schema.Schema.Type<typeof BodyValue>;\n\n/** A body part reference (the `partId` keys into `Email.bodyValues`; `blobId` fetches raw bytes). */\nexport const EmailBodyPart = Schema.Struct({\n partId: Schema.optional(Schema.NullOr(Schema.String)),\n blobId: Schema.optional(Schema.NullOr(Schema.String)),\n size: Schema.optional(Schema.Number),\n type: Schema.optional(Schema.String),\n charset: Schema.optional(Schema.NullOr(Schema.String)),\n /** Attachment filename, present on parts listed in `Email.attachments`. */\n name: Schema.optional(Schema.NullOr(Schema.String)),\n /** MIME `Content-Disposition` (`attachment` or `inline`), present on parts listed in `Email.attachments`. */\n disposition: Schema.optional(Schema.NullOr(Schema.String)),\n /** The part's `Content-ID` header (RFC 8621 §4.1.4), if any — matches a `cid:` reference in an HTML body. */\n cid: Schema.optional(Schema.NullOr(Schema.String)),\n});\nexport type EmailBodyPart = Schema.Schema.Type<typeof EmailBodyPart>;\n\n/** An email (RFC 8621 §4). Only the properties requested in `Email/get` are present. */\nexport const Email = Schema.Struct({\n id: Schema.String,\n blobId: Schema.optional(Schema.String),\n // Server-set and always present on a fetched Email (RFC 8621 §4.1.1); `EMAIL_PROPERTIES` requests it.\n threadId: Schema.String,\n mailboxIds: Schema.optional(Schema.Record(Schema.String, Schema.Boolean)),\n keywords: Schema.optional(Schema.Record(Schema.String, Schema.Boolean)),\n from: Schema.optional(Schema.NullOr(Schema.Array(EmailAddress))),\n to: Schema.optional(Schema.NullOr(Schema.Array(EmailAddress))),\n cc: Schema.optional(Schema.NullOr(Schema.Array(EmailAddress))),\n bcc: Schema.optional(Schema.NullOr(Schema.Array(EmailAddress))),\n subject: Schema.optional(Schema.NullOr(Schema.String)),\n receivedAt: Schema.String,\n sentAt: Schema.optional(Schema.NullOr(Schema.String)),\n preview: Schema.optional(Schema.NullOr(Schema.String)),\n messageId: Schema.optional(Schema.NullOr(Schema.Array(Schema.String))),\n inReplyTo: Schema.optional(Schema.NullOr(Schema.Array(Schema.String))),\n references: Schema.optional(Schema.NullOr(Schema.Array(Schema.String))),\n bodyValues: Schema.optional(Schema.Record(Schema.String, BodyValue)),\n textBody: Schema.optional(Schema.Array(EmailBodyPart)),\n htmlBody: Schema.optional(Schema.Array(EmailBodyPart)),\n /** Non-body parts (RFC 8621 §4.1.4) — the attachments proper, distinct from `textBody`/`htmlBody`. */\n attachments: Schema.optional(Schema.Array(EmailBodyPart)),\n});\nexport type Email = Schema.Schema.Type<typeof Email>;\n\n/** A sending identity (RFC 8621 §6); `email` is an address the server permits as `from`. */\nexport const Identity = Schema.Struct({\n id: Schema.String,\n name: Schema.optional(Schema.NullOr(Schema.String)),\n email: Schema.String,\n});\nexport type Identity = Schema.Schema.Type<typeof Identity>;\n\n//\n// Method-result schemas.\n//\n\nexport const MailboxGetResult = Schema.Struct({\n accountId: Schema.optional(Schema.String),\n state: Schema.optional(Schema.String),\n list: Schema.Array(Mailbox),\n notFound: Schema.optional(Schema.NullOr(Schema.Array(Schema.String))),\n});\nexport type MailboxGetResult = Schema.Schema.Type<typeof MailboxGetResult>;\n\nexport const EmailQueryResult = Schema.Struct({\n accountId: Schema.optional(Schema.String),\n queryState: Schema.optional(Schema.String),\n position: Schema.optional(Schema.Number),\n total: Schema.optional(Schema.Number),\n limit: Schema.optional(Schema.Number),\n ids: Schema.Array(Schema.String),\n});\nexport type EmailQueryResult = Schema.Schema.Type<typeof EmailQueryResult>;\n\nexport const EmailGetResult = Schema.Struct({\n accountId: Schema.optional(Schema.String),\n state: Schema.optional(Schema.String),\n list: Schema.Array(Email),\n notFound: Schema.optional(Schema.NullOr(Schema.Array(Schema.String))),\n});\nexport type EmailGetResult = Schema.Schema.Type<typeof EmailGetResult>;\n\n/** `Email/changes` delta since an opaque `sinceState` token (RFC 8621 §4.3 / RFC 8620 §5.2). */\nexport const EmailChangesResult = Schema.Struct({\n accountId: Schema.optional(Schema.String),\n oldState: Schema.String,\n newState: Schema.String,\n hasMoreChanges: Schema.Boolean,\n created: Schema.Array(Schema.String),\n updated: Schema.Array(Schema.String),\n destroyed: Schema.Array(Schema.String),\n});\nexport type EmailChangesResult = Schema.Schema.Type<typeof EmailChangesResult>;\n\nexport const IdentityGetResult = Schema.Struct({\n accountId: Schema.optional(Schema.String),\n state: Schema.optional(Schema.String),\n list: Schema.Array(Identity),\n notFound: Schema.optional(Schema.NullOr(Schema.Array(Schema.String))),\n});\nexport type IdentityGetResult = Schema.Schema.Type<typeof IdentityGetResult>;\n\nexport const EmailSetResult = Schema.Struct({\n accountId: Schema.optional(Schema.String),\n oldState: Schema.optional(Schema.NullOr(Schema.String)),\n newState: Schema.optional(Schema.String),\n created: Schema.optional(\n Schema.NullOr(\n Schema.Record(\n Schema.String,\n Schema.Struct({\n id: Schema.String,\n blobId: Schema.optional(Schema.String),\n threadId: Schema.optional(Schema.String),\n size: Schema.optional(Schema.Number),\n }),\n ),\n ),\n ),\n updated: Schema.optional(Schema.NullOr(Schema.Record(Schema.String, Schema.Unknown))),\n destroyed: Schema.optional(Schema.NullOr(Schema.Array(Schema.String))),\n notCreated: Schema.optional(\n Schema.NullOr(\n Schema.Record(\n Schema.String,\n Schema.Struct({ type: Schema.String, description: Schema.optional(Schema.NullOr(Schema.String)) }),\n ),\n ),\n ),\n notUpdated: Schema.optional(\n Schema.NullOr(\n Schema.Record(\n Schema.String,\n Schema.Struct({ type: Schema.String, description: Schema.optional(Schema.NullOr(Schema.String)) }),\n ),\n ),\n ),\n notDestroyed: Schema.optional(\n Schema.NullOr(\n Schema.Record(\n Schema.String,\n Schema.Struct({ type: Schema.String, description: Schema.optional(Schema.NullOr(Schema.String)) }),\n ),\n ),\n ),\n});\nexport type EmailSetResult = Schema.Schema.Type<typeof EmailSetResult>;\n\nexport const EmailSubmissionSetResult = Schema.Struct({\n accountId: Schema.optional(Schema.String),\n newState: Schema.optional(Schema.String),\n created: Schema.optional(Schema.NullOr(Schema.Record(Schema.String, Schema.Struct({ id: Schema.String })))),\n notCreated: Schema.optional(\n Schema.NullOr(\n Schema.Record(\n Schema.String,\n Schema.Struct({ type: Schema.String, description: Schema.optional(Schema.NullOr(Schema.String)) }),\n ),\n ),\n ),\n});\nexport type EmailSubmissionSetResult = Schema.Schema.Type<typeof EmailSubmissionSetResult>;\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Effect from 'effect/Effect';\nimport * as HttpClient from 'effect/http/HttpClient';\nimport * as HttpClientRequest from 'effect/http/HttpClientRequest';\n\nimport { withAuthorization } from '@dxos/compute-runtime';\n\nimport { JmapApiError } from '../../errors.ts';\nimport { JmapCredentials } from '../../services/jmap-credentials.ts';\nimport {\n MAIL_CAPABILITIES,\n REQUEST_RETRY,\n REQUEST_TIMEOUT,\n SUBMISSION_CAPABILITIES,\n getMethodResponse,\n jmapRequest,\n shouldRetry,\n} from '../Jmap/api.ts';\nimport {\n type EmailAddress,\n EmailChangesResult,\n EmailGetResult,\n EmailQueryResult,\n EmailSetResult,\n EmailSubmissionSetResult,\n IdentityGetResult,\n MailboxGetResult,\n} from './types.ts';\n\n/**\n * Resolved per-request context: the session `apiUrl`, the mail account id, and (optionally) the\n * session's blob `downloadUrl` template (RFC 8620 §6.2). Most operations (mailboxGet, emailQuery,\n * send, delete, …) don't need it and construct a `Target` without it; only the attachment-fetching\n * path populates it from `Jmap.Session.downloadUrl`, so {@link downloadBlob} is the sole consumer\n * that requires it — absent here just means \"this call site never populated it\", not \"the server\n * didn't advertise one\" (every real session does).\n */\nexport type Target = {\n readonly apiUrl: string;\n readonly accountId: string;\n readonly downloadUrl?: string;\n};\n\n/** Expands a JMAP `downloadUrl` URI Template (RFC 6570 level 1) with the given variables. */\nconst expandDownloadUrl = (\n template: string,\n variables: { accountId: string; blobId: string; type: string; name: string },\n): string =>\n template.replace(/\\{(\\w+)\\}/g, (_, key: string) =>\n key in variables ? encodeURIComponent(variables[key as keyof typeof variables]) : '',\n );\n\n/**\n * Downloads a blob's raw bytes via the session's `downloadUrl` template. `name`/`type` are advisory\n * (they only affect the response's `Content-Disposition`/`Accept`), not required for correctness.\n */\nexport const downloadBlob = Effect.fn('downloadBlob')(function* (\n target: Target,\n blobId: string,\n options: { name?: string; type?: string } = {},\n) {\n if (!target.downloadUrl) {\n return yield* Effect.fail(new JmapApiError(undefined, 'Session has no downloadUrl.'));\n }\n const url = expandDownloadUrl(target.downloadUrl, {\n accountId: target.accountId,\n blobId,\n name: options.name ?? blobId,\n type: options.type ?? 'application/octet-stream',\n });\n\n const { token } = yield* JmapCredentials;\n const httpClient = yield* HttpClient.HttpClient.pipe(Effect.map(withAuthorization(token, 'Bearer')));\n\n // Mapped to `JmapApiError` before `Effect.timeout`/`Effect.retry` so `shouldRetry` can actually\n // distinguish a permanent 4xx from a transient failure — mirrors `jmapRequest`.\n const buffer = yield* HttpClientRequest.get(url).pipe(\n httpClient.execute,\n Effect.flatMap((response) => response.arrayBuffer),\n Effect.mapError(asJmapDownloadError),\n Effect.timeout(REQUEST_TIMEOUT),\n Effect.retry({ schedule: REQUEST_RETRY, while: shouldRetry }),\n Effect.scoped,\n Effect.mapError(asJmapDownloadError),\n );\n return new Uint8Array(buffer);\n});\n\n/** Collapses transport/decode failures into a typed {@link JmapApiError} (mirrors `Jmap/api.ts`). */\nconst asJmapDownloadError = (error: unknown): JmapApiError =>\n error instanceof JmapApiError\n ? error\n : new JmapApiError(undefined, error instanceof Error ? error.message : String(error));\n\n/** Email properties fetched by {@link emailGet} — enough for the mapper to build a Message. */\nexport const EMAIL_PROPERTIES = [\n 'id',\n 'blobId',\n 'threadId',\n 'mailboxIds',\n 'keywords',\n 'from',\n 'to',\n 'cc',\n 'subject',\n 'receivedAt',\n 'sentAt',\n 'preview',\n 'messageId',\n 'inReplyTo',\n 'references',\n 'bodyValues',\n 'textBody',\n 'htmlBody',\n 'attachments',\n] as const;\n\n/** Lists all folders (mailboxes) in the account (RFC 8621 §2.3). */\nexport const mailboxGet = Effect.fn('mailboxGet')(function* (target: Target) {\n const response = yield* jmapRequest(target.apiUrl, {\n using: MAIL_CAPABILITIES,\n methodCalls: [['Mailbox/get', { accountId: target.accountId, ids: null }, '0']],\n });\n return yield* getMethodResponse(response, '0', MailboxGetResult);\n});\n\n/** Queries email ids matching a filter (RFC 8621 §4.4). */\nexport const emailQuery = Effect.fn('emailQuery')(function* (\n target: Target,\n options: {\n filter?: unknown;\n sort?: readonly { property: string; isAscending?: boolean }[];\n position?: number;\n limit?: number;\n calculateTotal?: boolean;\n } = {},\n) {\n const args: Record<string, unknown> = { accountId: target.accountId };\n if (options.filter !== undefined) {\n args.filter = options.filter;\n }\n if (options.sort !== undefined) {\n args.sort = options.sort;\n }\n if (options.position !== undefined) {\n args.position = options.position;\n }\n if (options.limit !== undefined) {\n args.limit = options.limit;\n }\n if (options.calculateTotal !== undefined) {\n args.calculateTotal = options.calculateTotal;\n }\n\n const response = yield* jmapRequest(target.apiUrl, {\n using: MAIL_CAPABILITIES,\n methodCalls: [['Email/query', args, '0']],\n });\n return yield* getMethodResponse(response, '0', EmailQueryResult);\n});\n\n/** Fetches emails by id with decoded HTML and text body values (RFC 8621 §4.2). */\nexport const emailGet = Effect.fn('emailGet')(function* (\n target: Target,\n ids: readonly string[],\n properties: readonly string[] = EMAIL_PROPERTIES,\n) {\n const response = yield* jmapRequest(target.apiUrl, {\n using: MAIL_CAPABILITIES,\n methodCalls: [\n [\n 'Email/get',\n { accountId: target.accountId, ids, properties, fetchTextBodyValues: true, fetchHTMLBodyValues: true },\n '0',\n ],\n ],\n });\n return yield* getMethodResponse(response, '0', EmailGetResult);\n});\n\n/**\n * Fetches the delta of email changes since an opaque `sinceState` token (RFC 8621 §4.3). A server that\n * can't compute the delta (state too old / evicted) returns a `cannotCalculateChanges` method error,\n * surfaced as a {@link JmapApiError} with that `type` — the caller's cue to fall back to a full scan.\n * The token to pass comes from a prior `Email/get` `state` (NOT `Email/query` `queryState`).\n */\nexport const emailChanges = Effect.fn('emailChanges')(function* (\n target: Target,\n sinceState: string,\n maxChanges?: number,\n) {\n const args: Record<string, unknown> = { accountId: target.accountId, sinceState };\n if (maxChanges !== undefined) {\n args.maxChanges = maxChanges;\n }\n const response = yield* jmapRequest(target.apiUrl, {\n using: MAIL_CAPABILITIES,\n methodCalls: [['Email/changes', args, '0']],\n });\n return yield* getMethodResponse(response, '0', EmailChangesResult);\n});\n\n/** Lists the account's sending identities (RFC 8621 §6.2). */\nexport const identityGet = Effect.fn('identityGet')(function* (target: Target) {\n const response = yield* jmapRequest(target.apiUrl, {\n using: SUBMISSION_CAPABILITIES,\n methodCalls: [['Identity/get', { accountId: target.accountId, ids: null }, '0']],\n });\n return yield* getMethodResponse(response, '0', IdentityGetResult);\n});\n\n/** Patches a single email (e.g. replace `mailboxIds` to move to Trash). Idempotent, so retryable. */\nexport const emailSetUpdate = Effect.fn('emailSetUpdate')(function* (\n target: Target,\n emailId: string,\n patch: Record<string, unknown>,\n) {\n const response = yield* jmapRequest(target.apiUrl, {\n using: MAIL_CAPABILITIES,\n methodCalls: [['Email/set', { accountId: target.accountId, update: { [emailId]: patch } }, '0']],\n });\n const result = yield* getMethodResponse(response, '0', EmailSetResult);\n const error = result.notUpdated?.[emailId];\n if (error) {\n return yield* Effect.fail(new JmapApiError(undefined, error.description ?? error.type, error.type));\n }\n return result;\n});\n\n/**\n * Creates a draft and submits it for delivery in a single batched request. Not retried (a retry\n * could double-send). Returns the created email's id and thread id.\n */\nexport const submitEmail = Effect.fn('submitEmail')(function* (\n target: Target,\n args: {\n identityId: string;\n draftsMailboxId: string;\n sentMailboxId: string;\n draft: {\n from: readonly EmailAddress[];\n to: readonly EmailAddress[];\n cc?: readonly EmailAddress[];\n bcc?: readonly EmailAddress[];\n subject?: string;\n inReplyTo?: readonly string[];\n references?: readonly string[];\n text: string;\n };\n },\n) {\n const { identityId, draftsMailboxId, sentMailboxId, draft } = args;\n const draftCreate: Record<string, unknown> = {\n mailboxIds: { [draftsMailboxId]: true },\n keywords: { $draft: true, $seen: true },\n from: draft.from,\n to: draft.to,\n bodyValues: { body: { value: draft.text } },\n textBody: [{ partId: 'body', type: 'text/plain' }],\n };\n if (draft.cc && draft.cc.length > 0) {\n draftCreate.cc = draft.cc;\n }\n if (draft.bcc && draft.bcc.length > 0) {\n draftCreate.bcc = draft.bcc;\n }\n if (draft.subject !== undefined) {\n draftCreate.subject = draft.subject;\n }\n if (draft.inReplyTo && draft.inReplyTo.length > 0) {\n draftCreate.inReplyTo = draft.inReplyTo;\n }\n if (draft.references && draft.references.length > 0) {\n draftCreate.references = draft.references;\n }\n\n const response = yield* jmapRequest(\n target.apiUrl,\n {\n using: SUBMISSION_CAPABILITIES,\n methodCalls: [\n ['Email/set', { accountId: target.accountId, create: { draft: draftCreate } }, '0'],\n [\n 'EmailSubmission/set',\n {\n accountId: target.accountId,\n create: { sub: { emailId: '#draft', identityId } },\n onSuccessUpdateEmail: {\n '#sub': {\n [`mailboxIds/${draftsMailboxId}`]: null,\n [`mailboxIds/${sentMailboxId}`]: true,\n 'keywords/$draft': null,\n },\n },\n },\n '1',\n ],\n ],\n },\n { retry: false },\n );\n\n const setResult = yield* getMethodResponse(response, '0', EmailSetResult);\n const created = setResult.created?.draft;\n if (!created) {\n const error = setResult.notCreated?.draft;\n return yield* Effect.fail(\n new JmapApiError(undefined, error?.description ?? error?.type ?? 'Draft was not created.', error?.type),\n );\n }\n\n const submissionResult = yield* getMethodResponse(response, '1', EmailSubmissionSetResult);\n if (!submissionResult.created?.sub) {\n const error = submissionResult.notCreated?.sub;\n return yield* Effect.fail(\n new JmapApiError(undefined, error?.description ?? error?.type ?? 'Email submission failed.', error?.type),\n );\n }\n\n return { id: created.id, threadId: created.threadId };\n});\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport { subDays, subMonths, subWeeks, subYears } from 'date-fns';\nimport * as Match from 'effect/Match';\nimport * as Option from 'effect/Option';\n\nimport { type Filter, type FilterCondition, type FilterOperator } from '../Jmap/index.ts';\nimport { type Mailbox } from './types.ts';\n\n/** Context for {@link parseMailQuery}: a clock (for relative dates) and a label/folder resolver. */\nexport type ParseContext = {\n readonly now: Date;\n /** Resolves a `label:`/`in:` name or system role to a JMAP mailbox id. */\n readonly resolveMailbox: (nameOrRole: string) => Option.Option<string>;\n};\n\ntype Token =\n | { readonly _tag: 'or' }\n | { readonly _tag: 'term'; readonly negate: boolean; readonly op: Option.Option<string>; readonly value: string };\n\n/**\n * Translates a Gmail-like query string into a JMAP `Email/query` filter (RFC 8621 §4.4.1).\n *\n * Supported operators: `from:`/`to:`/`cc:`/`bcc:`/`subject:`/`body:`, `label:`/`in:` (resolved to a\n * mailbox id), `is:unread|read|starred|flagged|unstarred|draft|answered`, `has:attachment`,\n * `after:`/`before:` (`YYYY/MM/DD` or `YYYY-MM-DD`), `newer_than:`/`older_than:` (e.g. `7d`, `2w`,\n * `3m`, `1y`), `larger:`/`smaller:` (e.g. `10M`, `500k`), `list:`/`deliveredto:` (header match),\n * quoted phrases, `-` negation, `OR` groups, and bare words (full-text). Space-separated terms are\n * AND-ed. Returns `None` for an empty query, or one whose terms all fail to resolve (e.g. an unknown\n * label).\n */\nexport const parseMailQuery = (query: string, ctx: ParseContext): Option.Option<Filter> =>\n buildFilter(tokenize(query), ctx);\n\n/** Resolves a label/folder name (case-insensitive) or a system role/alias to a mailbox id. */\nexport const resolveMailboxByNameOrRole = (folders: readonly Mailbox[], nameOrRole: string): Option.Option<string> => {\n const lowered = nameOrRole.toLowerCase();\n const role = ROLE_ALIASES[lowered] ?? lowered;\n const match =\n folders.find((folder) => folder.role === role) ?? folders.find((folder) => folder.name.toLowerCase() === lowered);\n return Option.fromNullishOr(match?.id);\n};\n\n//\n// Tokenizer.\n//\n\n// A token is an optional `-`, optional `op:` prefix, then a `\"quoted\"` value or a non-space run.\nconst TOKEN_RE = /-?(?:[A-Za-z_]+:)?\"[^\"]*\"|\\S+/g;\n\nconst tokenize = (query: string): readonly Token[] => (query.match(TOKEN_RE) ?? []).map(parseToken);\n\nconst parseToken = (raw: string): Token => {\n if (raw === 'OR') {\n return { _tag: 'or' };\n }\n const negate = raw.startsWith('-');\n const rest = negate ? raw.slice(1) : raw;\n const colon = rest.indexOf(':');\n if (colon > 0 && /^[A-Za-z_]+$/.test(rest.slice(0, colon))) {\n return {\n _tag: 'term',\n negate,\n op: Option.some(rest.slice(0, colon).toLowerCase()),\n value: stripQuotes(rest.slice(colon + 1)),\n };\n }\n return { _tag: 'term', negate, op: Option.none(), value: stripQuotes(rest) };\n};\n\nconst stripQuotes = (value: string): string =>\n value.length >= 2 && value.startsWith('\"') && value.endsWith('\"') ? value.slice(1, -1) : value;\n\n//\n// Folding tokens into a filter tree. Space-separated terms AND together; an `OR` token merges the\n// next term with the previous operand. Terms that resolve to `None` (unknown label, empty value) are\n// dropped.\n//\n\nconst buildFilter = (tokens: readonly Token[], ctx: ParseContext): Option.Option<Filter> => {\n const { operands } = tokens.reduce<{ operands: readonly Filter[]; pendingOr: boolean }>(\n (state, token) => {\n if (token._tag === 'or') {\n return { ...state, pendingOr: state.operands.length > 0 };\n }\n const leaf = buildTerm(token, ctx);\n if (Option.isNone(leaf)) {\n // A dropped term (unknown label, empty value) consumes any pending OR: the next valid term\n // must not merge with the previous operand unless its own `or` token immediately precedes it.\n return { ...state, pendingOr: false };\n }\n const previous = state.pendingOr ? state.operands[state.operands.length - 1] : undefined;\n return previous !== undefined\n ? { operands: [...state.operands.slice(0, -1), mergeOr(previous, leaf.value)], pendingOr: false }\n : { operands: [...state.operands, leaf.value], pendingOr: false };\n },\n { operands: [], pendingOr: false },\n );\n\n return Match.value(operands.length).pipe(\n Match.when(0, () => Option.none<Filter>()),\n Match.when(1, () => Option.fromNullishOr(operands[0])),\n Match.orElse(() => Option.some<Filter>({ operator: 'AND', conditions: operands })),\n );\n};\n\nconst mergeOr = (previous: Filter, next: Filter): FilterOperator =>\n isOperator(previous) && previous.operator === 'OR'\n ? { operator: 'OR', conditions: [...previous.conditions, next] }\n : { operator: 'OR', conditions: [previous, next] };\n\nconst isOperator = (filter: Filter): filter is FilterOperator => 'operator' in filter;\n\n/** Whether a filter restricts the mailbox scope (`inMailbox`/`inMailboxOtherThan`), recursively. */\nexport const filterScopesMailbox = (filter: Filter): boolean =>\n isOperator(filter)\n ? filter.conditions.some(filterScopesMailbox)\n : filter.inMailbox !== undefined || filter.inMailboxOtherThan !== undefined;\n\nconst buildTerm = (token: Extract<Token, { _tag: 'term' }>, ctx: ParseContext): Option.Option<Filter> =>\n buildLeaf(token.op, token.value, ctx).pipe(Option.map((leaf) => (token.negate ? negate(leaf) : leaf)));\n\nconst negate = (filter: Filter): FilterOperator => ({ operator: 'NOT', conditions: [filter] });\n\n//\n// Leaf construction (operator → JMAP FilterCondition).\n//\n\nconst buildLeaf = (op: Option.Option<string>, value: string, ctx: ParseContext): Option.Option<Filter> =>\n op.pipe(\n Option.match({\n onNone: () => textLeaf(value),\n onSome: (operator) => buildOperatorLeaf(operator, value, ctx),\n }),\n );\n\nconst buildOperatorLeaf = (operator: string, value: string, ctx: ParseContext): Option.Option<Filter> =>\n Match.value(operator).pipe(\n Match.whenOr('from', 'to', 'cc', 'bcc', 'subject', 'body', (field) =>\n condLeaf(value, STRING_FIELD_LEAVES[field](value)),\n ),\n Match.whenOr('label', 'in', () => ctx.resolveMailbox(value).pipe(Option.map((id) => ({ inMailbox: id })))),\n Match.when('is', () => Option.fromNullishOr(IS_LEAVES[value.toLowerCase()])),\n Match.when('has', () =>\n value.toLowerCase() === 'attachment' ? Option.some<Filter>({ hasAttachment: true }) : Option.none<Filter>(),\n ),\n Match.whenOr('after', 'newer', () => dateLeaf(value, 'after')),\n Match.whenOr('before', 'older', () => dateLeaf(value, 'before')),\n Match.when('newer_than', () => relativeDateLeaf(value, ctx.now, 'after')),\n Match.when('older_than', () => relativeDateLeaf(value, ctx.now, 'before')),\n Match.when('larger', () => sizeLeaf(value, 'minSize')),\n Match.when('smaller', () => sizeLeaf(value, 'maxSize')),\n Match.when('list', () => headerLeaf('List-Id', value)),\n Match.when('deliveredto', () => headerLeaf('Delivered-To', value)),\n // Unknown operator: keep the literal `op:value` as a full-text term (mirrors Gmail's fallback).\n Match.orElse(() => textLeaf(`${operator}:${value}`)),\n );\n\ntype StringField = 'from' | 'to' | 'cc' | 'bcc' | 'subject' | 'body';\n\nconst STRING_FIELD_LEAVES: Record<StringField, (value: string) => FilterCondition> = {\n from: (value) => ({ from: value }),\n to: (value) => ({ to: value }),\n cc: (value) => ({ cc: value }),\n bcc: (value) => ({ bcc: value }),\n subject: (value) => ({ subject: value }),\n body: (value) => ({ body: value }),\n};\n\nconst IS_LEAVES: Record<string, Filter> = {\n unread: { notKeyword: '$seen' },\n read: { hasKeyword: '$seen' },\n starred: { hasKeyword: '$flagged' },\n flagged: { hasKeyword: '$flagged' },\n unstarred: { notKeyword: '$flagged' },\n unflagged: { notKeyword: '$flagged' },\n draft: { hasKeyword: '$draft' },\n answered: { hasKeyword: '$answered' },\n replied: { hasKeyword: '$answered' },\n};\n\nconst ROLE_ALIASES: Record<string, string> = { spam: 'junk', bin: 'trash', deleted: 'trash' };\n\nconst SIZE_UNITS: Record<string, number> = { '': 1, 'k': 1024, 'm': 1024 * 1024, 'g': 1024 * 1024 * 1024 };\nconst DATE_RE = /^(\\d{4})[/-](\\d{1,2})[/-](\\d{1,2})$/;\nconst RELATIVE_RE = /^(\\d+)([dwmy])$/;\nconst SIZE_RE = /^(\\d+)([kmg]?)b?$/i;\n\n/** Wraps a built condition in `Some`, or `None` when the value is blank. */\nconst condLeaf = (value: string, condition: Filter): Option.Option<Filter> =>\n value.trim().length === 0 ? Option.none() : Option.some(condition);\n\nconst textLeaf = (value: string): Option.Option<Filter> => condLeaf(value, { text: value });\n\nconst headerLeaf = (name: string, value: string): Option.Option<Filter> => condLeaf(value, { header: [name, value] });\n\nconst dateLeaf = (value: string, bound: 'after' | 'before'): Option.Option<Filter> => {\n const match = DATE_RE.exec(value);\n if (!match) {\n return Option.none();\n }\n const iso = new Date(Date.UTC(Number(match[1]), Number(match[2]) - 1, Number(match[3]))).toISOString();\n return Option.some(bound === 'after' ? { after: iso } : { before: iso });\n};\n\nconst relativeDateLeaf = (value: string, now: Date, bound: 'after' | 'before'): Option.Option<Filter> => {\n const match = RELATIVE_RE.exec(value.toLowerCase());\n if (!match) {\n return Option.none();\n }\n const amount = Number(match[1]);\n const date = Match.value(match[2]).pipe(\n Match.when('w', () => subWeeks(now, amount)),\n Match.when('m', () => subMonths(now, amount)),\n Match.when('y', () => subYears(now, amount)),\n Match.orElse(() => subDays(now, amount)),\n );\n const iso = date.toISOString();\n return Option.some(bound === 'after' ? { after: iso } : { before: iso });\n};\n\nconst sizeLeaf = (value: string, bound: 'minSize' | 'maxSize'): Option.Option<Filter> => {\n const match = SIZE_RE.exec(value.toLowerCase());\n if (!match) {\n return Option.none();\n }\n const bytes = Number(match[1]) * (SIZE_UNITS[match[2] ?? ''] ?? 1);\n return Option.some(bound === 'minSize' ? { minSize: bytes } : { maxSize: bytes });\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\nexport * from './api.ts';\nexport * from './types.ts';\nexport * from './query.ts';\n"],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import * as ActivationEvents from "@dxos/app-framework/ActivationEvents";
|
|
2
|
+
import * as Capability from "@dxos/app-framework/Capability";
|
|
3
|
+
import * as AppCapability from "@dxos/app-toolkit/AppCapability";
|
|
4
|
+
import * as ConnectorEvents from "@dxos/plugin-connector/ConnectorEvents";
|
|
5
|
+
import * as ConnectorSpec from "@dxos/plugin-connector/ConnectorSpec";
|
|
6
|
+
import * as InboxCapabilities from "@dxos/plugin-inbox/InboxCapabilities";
|
|
7
|
+
import { translations } from "#translations";
|
|
8
|
+
//#region src/capabilities/gen/browser.ts
|
|
9
|
+
var Connector = Capability.lazyModule("JmapConnector", {
|
|
10
|
+
provides: [ConnectorSpec.Connector],
|
|
11
|
+
activatesOn: ConnectorEvents.Start
|
|
12
|
+
}, () => import("./chunk-connector.mjs"));
|
|
13
|
+
var MailSend = Capability.lazyModule("JmapMailSend", { provides: [InboxCapabilities.MailSendOperation] }, () => import("./chunk-mail-send.mjs"));
|
|
14
|
+
var OperationHandler = AppCapability.operationHandler(() => import("./chunk-operation-handler.mjs"), { activatesOn: ActivationEvents.Idle });
|
|
15
|
+
var Translations = AppCapability.translations(translations);
|
|
16
|
+
//#endregion
|
|
17
|
+
export { Connector, MailSend, OperationHandler, Translations };
|
|
18
|
+
|
|
19
|
+
//# sourceMappingURL=capabilities.browser.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capabilities.browser.mjs","names":[],"sources":["../../src/capabilities/gen/browser.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\n// GENERATED by dx-plugin — do not edit. Sliced from ../index.ts for the 'browser' condition.\n\nimport * as ActivationEvents from '@dxos/app-framework/ActivationEvents';\nimport * as Capability from '@dxos/app-framework/Capability';\nimport * as AppCapability from '@dxos/app-toolkit/AppCapability';\nimport * as ConnectorEvents from '@dxos/plugin-connector/ConnectorEvents';\nimport * as ConnectorSpec from '@dxos/plugin-connector/ConnectorSpec';\nimport * as InboxCapabilities from '@dxos/plugin-inbox/InboxCapabilities';\n\nimport { translations } from '#translations';\n\nexport const Connector = Capability.lazyModule(\n 'JmapConnector',\n { provides: [ConnectorSpec.Connector], activatesOn: ConnectorEvents.Start },\n () => import('../connector.ts'),\n);\n\nexport const MailSend = Capability.lazyModule(\n 'JmapMailSend',\n { provides: [InboxCapabilities.MailSendOperation] },\n () => import('../mail-send.ts'),\n);\n\nexport const OperationHandler = AppCapability.operationHandler(() => import('../operation-handler.ts'), {\n activatesOn: ActivationEvents.Idle,\n});\n\nexport const Translations = AppCapability.translations(translations);\n"],"mappings":";;;;;;;;AAeA,IAAa,YAAY,WAAW,WAClC,iBACA;CAAE,UAAU,CAAC,cAAc,SAAS;CAAG,aAAa,gBAAgB;AAAM,SACpE,OAAO,wBACf;AAEA,IAAa,WAAW,WAAW,WACjC,gBACA,EAAE,UAAU,CAAC,kBAAkB,iBAAiB,EAAE,SAC5C,OAAO,wBACf;AAEA,IAAa,mBAAmB,cAAc,uBAAuB,OAAO,kCAA4B,EACtG,aAAa,iBAAiB,KAChC,CAAC;AAED,IAAa,eAAe,cAAc,aAAa,YAAY"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"capabilities.mjs","names":[],"sources":["../../src/capabilities/index.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport * as ActivationEvents from '@dxos/app-framework/ActivationEvents';\nimport * as Capability from '@dxos/app-framework/Capability';\nimport * as AppCapability from '@dxos/app-toolkit/AppCapability';\nimport * as ConnectorEvents from '@dxos/plugin-connector/ConnectorEvents';\nimport * as ConnectorSpec from '@dxos/plugin-connector/ConnectorSpec';\nimport * as InboxCapabilities from '@dxos/plugin-inbox/InboxCapabilities';\n\nimport { translations } from '#translations';\n\nexport const Connector = Capability.lazyModule(\n 'JmapConnector',\n { provides: [ConnectorSpec.Connector], activatesOn: ConnectorEvents.Start },\n () => import('./connector'),\n);\nexport const MailSend = Capability.lazyModule(\n 'JmapMailSend',\n { provides: [InboxCapabilities.MailSendOperation] },\n () => import('./mail-send'),\n);\nexport const OperationHandler = AppCapability.operationHandler(() => import('./operation-handler'), {\n activatesOn: ActivationEvents.Idle,\n});\nexport const Translations = AppCapability.translations(translations);\n"],"mappings":";;;;;;;;AAaA,IAAa,YAAY,WAAW,WAClC,iBACA;CAAE,UAAU,CAAC,cAAc,SAAS;CAAG,aAAa,gBAAgB;AAAM,SACpE,OAAO,wBACf;AACA,IAAa,WAAW,WAAW,WACjC,gBACA,EAAE,UAAU,CAAC,kBAAkB,iBAAiB,EAAE,SAC5C,OAAO,wBACf;AACA,IAAa,mBAAmB,cAAc,uBAAuB,OAAO,
|
|
1
|
+
{"version":3,"file":"capabilities.mjs","names":[],"sources":["../../src/capabilities/index.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport * as ActivationEvents from '@dxos/app-framework/ActivationEvents';\nimport * as Capability from '@dxos/app-framework/Capability';\nimport * as AppCapability from '@dxos/app-toolkit/AppCapability';\nimport * as ConnectorEvents from '@dxos/plugin-connector/ConnectorEvents';\nimport * as ConnectorSpec from '@dxos/plugin-connector/ConnectorSpec';\nimport * as InboxCapabilities from '@dxos/plugin-inbox/InboxCapabilities';\n\nimport { translations } from '#translations';\n\nexport const Connector = Capability.lazyModule(\n 'JmapConnector',\n { provides: [ConnectorSpec.Connector], activatesOn: ConnectorEvents.Start },\n () => import('./connector.ts'),\n);\nexport const MailSend = Capability.lazyModule(\n 'JmapMailSend',\n { provides: [InboxCapabilities.MailSendOperation] },\n () => import('./mail-send.ts'),\n);\nexport const OperationHandler = AppCapability.operationHandler(() => import('./operation-handler.ts'), {\n activatesOn: ActivationEvents.Idle,\n});\nexport const Translations = AppCapability.translations(translations);\n"],"mappings":";;;;;;;;AAaA,IAAa,YAAY,WAAW,WAClC,iBACA;CAAE,UAAU,CAAC,cAAc,SAAS;CAAG,aAAa,gBAAgB;AAAM,SACpE,OAAO,wBACf;AACA,IAAa,WAAW,WAAW,WACjC,gBACA,EAAE,UAAU,CAAC,kBAAkB,iBAAiB,EAAE,SAC5C,OAAO,wBACf;AACA,IAAa,mBAAmB,cAAc,uBAAuB,OAAO,kCAA2B,EACrG,aAAa,iBAAiB,KAChC,CAAC;AACD,IAAa,eAAe,cAAc,aAAa,YAAY"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"capabilities.node.mjs","names":[],"sources":["../../src/capabilities/gen/node.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\n// GENERATED by dx-plugin — do not edit. Sliced from ../index.ts for the 'node' condition.\n\nimport * as ActivationEvents from '@dxos/app-framework/ActivationEvents';\nimport * as Capability from '@dxos/app-framework/Capability';\nimport * as AppCapability from '@dxos/app-toolkit/AppCapability';\nimport * as ConnectorEvents from '@dxos/plugin-connector/ConnectorEvents';\nimport * as ConnectorSpec from '@dxos/plugin-connector/ConnectorSpec';\nimport * as InboxCapabilities from '@dxos/plugin-inbox/InboxCapabilities';\n\nimport { translations } from '#translations';\n\nexport const Connector = Capability.lazyModule(\n 'JmapConnector',\n { provides: [ConnectorSpec.Connector], activatesOn: ConnectorEvents.Start },\n () => import('../connector'),\n);\n\nexport const MailSend = Capability.lazyModule(\n 'JmapMailSend',\n { provides: [InboxCapabilities.MailSendOperation] },\n () => import('../mail-send'),\n);\n\nexport const OperationHandler = AppCapability.operationHandler(() => import('../operation-handler'), {\n activatesOn: ActivationEvents.Idle,\n});\n\nexport const Translations = AppCapability.translations(translations);\n"],"mappings":";;;;;;;;AAeA,IAAa,YAAY,WAAW,WAClC,iBACA;CAAE,UAAU,CAAC,cAAc,SAAS;CAAG,aAAa,gBAAgB;AAAM,SACpE,OAAO,wBACf;AAEA,IAAa,WAAW,WAAW,WACjC,gBACA,EAAE,UAAU,CAAC,kBAAkB,iBAAiB,EAAE,SAC5C,OAAO,wBACf;AAEA,IAAa,mBAAmB,cAAc,uBAAuB,OAAO,
|
|
1
|
+
{"version":3,"file":"capabilities.node.mjs","names":[],"sources":["../../src/capabilities/gen/node.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\n// GENERATED by dx-plugin — do not edit. Sliced from ../index.ts for the 'node' condition.\n\nimport * as ActivationEvents from '@dxos/app-framework/ActivationEvents';\nimport * as Capability from '@dxos/app-framework/Capability';\nimport * as AppCapability from '@dxos/app-toolkit/AppCapability';\nimport * as ConnectorEvents from '@dxos/plugin-connector/ConnectorEvents';\nimport * as ConnectorSpec from '@dxos/plugin-connector/ConnectorSpec';\nimport * as InboxCapabilities from '@dxos/plugin-inbox/InboxCapabilities';\n\nimport { translations } from '#translations';\n\nexport const Connector = Capability.lazyModule(\n 'JmapConnector',\n { provides: [ConnectorSpec.Connector], activatesOn: ConnectorEvents.Start },\n () => import('../connector.ts'),\n);\n\nexport const MailSend = Capability.lazyModule(\n 'JmapMailSend',\n { provides: [InboxCapabilities.MailSendOperation] },\n () => import('../mail-send.ts'),\n);\n\nexport const OperationHandler = AppCapability.operationHandler(() => import('../operation-handler.ts'), {\n activatesOn: ActivationEvents.Idle,\n});\n\nexport const Translations = AppCapability.translations(translations);\n"],"mappings":";;;;;;;;AAeA,IAAa,YAAY,WAAW,WAClC,iBACA;CAAE,UAAU,CAAC,cAAc,SAAS;CAAG,aAAa,gBAAgB;AAAM,SACpE,OAAO,wBACf;AAEA,IAAa,WAAW,WAAW,WACjC,gBACA,EAAE,UAAU,CAAC,kBAAkB,iBAAiB,EAAE,SAC5C,OAAO,wBACf;AAEA,IAAa,mBAAmB,cAAc,uBAAuB,OAAO,kCAA4B,EACtG,aAAa,iBAAiB,KAChC,CAAC;AAED,IAAa,eAAe,cAAc,aAAa,YAAY"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import * as ActivationEvents from "@dxos/app-framework/ActivationEvents";
|
|
2
|
+
import * as Capability from "@dxos/app-framework/Capability";
|
|
3
|
+
import * as AppCapability from "@dxos/app-toolkit/AppCapability";
|
|
4
|
+
import * as ConnectorEvents from "@dxos/plugin-connector/ConnectorEvents";
|
|
5
|
+
import * as ConnectorSpec from "@dxos/plugin-connector/ConnectorSpec";
|
|
6
|
+
import * as InboxCapabilities from "@dxos/plugin-inbox/InboxCapabilities";
|
|
7
|
+
import { translations } from "#translations";
|
|
8
|
+
//#region src/capabilities/gen/tauri.ts
|
|
9
|
+
var Connector = Capability.lazyModule("JmapConnector", {
|
|
10
|
+
provides: [ConnectorSpec.Connector],
|
|
11
|
+
activatesOn: ConnectorEvents.Start
|
|
12
|
+
}, () => import("./chunk-connector.mjs"));
|
|
13
|
+
var MailSend = Capability.lazyModule("JmapMailSend", { provides: [InboxCapabilities.MailSendOperation] }, () => import("./chunk-mail-send.mjs"));
|
|
14
|
+
var OperationHandler = AppCapability.operationHandler(() => import("./chunk-operation-handler.mjs"), { activatesOn: ActivationEvents.Idle });
|
|
15
|
+
var Translations = AppCapability.translations(translations);
|
|
16
|
+
//#endregion
|
|
17
|
+
export { Connector, MailSend, OperationHandler, Translations };
|
|
18
|
+
|
|
19
|
+
//# sourceMappingURL=capabilities.tauri.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capabilities.tauri.mjs","names":[],"sources":["../../src/capabilities/gen/tauri.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\n// GENERATED by dx-plugin — do not edit. Sliced from ../index.ts for the 'tauri' condition.\n\nimport * as ActivationEvents from '@dxos/app-framework/ActivationEvents';\nimport * as Capability from '@dxos/app-framework/Capability';\nimport * as AppCapability from '@dxos/app-toolkit/AppCapability';\nimport * as ConnectorEvents from '@dxos/plugin-connector/ConnectorEvents';\nimport * as ConnectorSpec from '@dxos/plugin-connector/ConnectorSpec';\nimport * as InboxCapabilities from '@dxos/plugin-inbox/InboxCapabilities';\n\nimport { translations } from '#translations';\n\nexport const Connector = Capability.lazyModule(\n 'JmapConnector',\n { provides: [ConnectorSpec.Connector], activatesOn: ConnectorEvents.Start },\n () => import('../connector.ts'),\n);\n\nexport const MailSend = Capability.lazyModule(\n 'JmapMailSend',\n { provides: [InboxCapabilities.MailSendOperation] },\n () => import('../mail-send.ts'),\n);\n\nexport const OperationHandler = AppCapability.operationHandler(() => import('../operation-handler.ts'), {\n activatesOn: ActivationEvents.Idle,\n});\n\nexport const Translations = AppCapability.translations(translations);\n"],"mappings":";;;;;;;;AAeA,IAAa,YAAY,WAAW,WAClC,iBACA;CAAE,UAAU,CAAC,cAAc,SAAS;CAAG,aAAa,gBAAgB;AAAM,SACpE,OAAO,wBACf;AAEA,IAAa,WAAW,WAAW,WACjC,gBACA,EAAE,UAAU,CAAC,kBAAkB,iBAAiB,EAAE,SAC5C,OAAO,wBACf;AAEA,IAAa,mBAAmB,cAAc,uBAAuB,OAAO,kCAA4B,EACtG,aAAa,iBAAiB,KAChC,CAAC;AAED,IAAa,eAAe,cAAc,aAAa,YAAY"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"capabilities.workerd.mjs","names":[],"sources":["../../src/capabilities/gen/workerd.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\n// GENERATED by dx-plugin — do not edit. Sliced from ../index.ts for the 'workerd' condition.\n\nimport * as ActivationEvents from '@dxos/app-framework/ActivationEvents';\nimport * as Capability from '@dxos/app-framework/Capability';\nimport * as AppCapability from '@dxos/app-toolkit/AppCapability';\nimport * as ConnectorEvents from '@dxos/plugin-connector/ConnectorEvents';\nimport * as ConnectorSpec from '@dxos/plugin-connector/ConnectorSpec';\nimport * as InboxCapabilities from '@dxos/plugin-inbox/InboxCapabilities';\n\nimport { translations } from '#translations';\n\nexport const Connector = Capability.lazyModule(\n 'JmapConnector',\n { provides: [ConnectorSpec.Connector], activatesOn: ConnectorEvents.Start },\n () => import('../connector'),\n);\n\nexport const MailSend = Capability.lazyModule(\n 'JmapMailSend',\n { provides: [InboxCapabilities.MailSendOperation] },\n () => import('../mail-send'),\n);\n\nexport const OperationHandler = AppCapability.operationHandler(() => import('../operation-handler'), {\n activatesOn: ActivationEvents.Idle,\n});\n\nexport const Translations = AppCapability.translations(translations);\n"],"mappings":";;;;;;;;AAeA,IAAa,YAAY,WAAW,WAClC,iBACA;CAAE,UAAU,CAAC,cAAc,SAAS;CAAG,aAAa,gBAAgB;AAAM,SACpE,OAAO,wBACf;AAEA,IAAa,WAAW,WAAW,WACjC,gBACA,EAAE,UAAU,CAAC,kBAAkB,iBAAiB,EAAE,SAC5C,OAAO,wBACf;AAEA,IAAa,mBAAmB,cAAc,uBAAuB,OAAO,
|
|
1
|
+
{"version":3,"file":"capabilities.workerd.mjs","names":[],"sources":["../../src/capabilities/gen/workerd.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\n// GENERATED by dx-plugin — do not edit. Sliced from ../index.ts for the 'workerd' condition.\n\nimport * as ActivationEvents from '@dxos/app-framework/ActivationEvents';\nimport * as Capability from '@dxos/app-framework/Capability';\nimport * as AppCapability from '@dxos/app-toolkit/AppCapability';\nimport * as ConnectorEvents from '@dxos/plugin-connector/ConnectorEvents';\nimport * as ConnectorSpec from '@dxos/plugin-connector/ConnectorSpec';\nimport * as InboxCapabilities from '@dxos/plugin-inbox/InboxCapabilities';\n\nimport { translations } from '#translations';\n\nexport const Connector = Capability.lazyModule(\n 'JmapConnector',\n { provides: [ConnectorSpec.Connector], activatesOn: ConnectorEvents.Start },\n () => import('../connector.ts'),\n);\n\nexport const MailSend = Capability.lazyModule(\n 'JmapMailSend',\n { provides: [InboxCapabilities.MailSendOperation] },\n () => import('../mail-send.ts'),\n);\n\nexport const OperationHandler = AppCapability.operationHandler(() => import('../operation-handler.ts'), {\n activatesOn: ActivationEvents.Idle,\n});\n\nexport const Translations = AppCapability.translations(translations);\n"],"mappings":";;;;;;;;AAeA,IAAa,YAAY,WAAW,WAClC,iBACA;CAAE,UAAU,CAAC,cAAc,SAAS;CAAG,aAAa,gBAAgB;AAAM,SACpE,OAAO,wBACf;AAEA,IAAa,WAAW,WAAW,WACjC,gBACA,EAAE,UAAU,CAAC,kBAAkB,iBAAiB,EAAE,SAC5C,OAAO,wBACf;AAEA,IAAa,mBAAmB,cAAc,uBAAuB,OAAO,kCAA4B,EACtG,aAAa,iBAAiB,KAChC,CAAC;AAED,IAAa,eAAe,cAAc,aAAa,YAAY"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
import { n as JmapCredentialInvalidError, t as JmapApiError } from "./chunk-errors.mjs";
|
|
1
2
|
import { r as JMAP_MAIL_CONNECTOR_ID, t as JMAP_DEFAULT_HOST } from "./chunk-constants.mjs";
|
|
2
|
-
import { t as JmapApiError } from "./chunk-errors.mjs";
|
|
3
3
|
import * as Capability from "@dxos/app-framework/Capability";
|
|
4
4
|
import * as ConnectorSpec from "@dxos/plugin-connector/ConnectorSpec";
|
|
5
5
|
import { JmapOperation } from "#types";
|
|
@@ -8,13 +8,13 @@ import { Format, Obj, Ref, Type } from "@dxos/echo";
|
|
|
8
8
|
import * as Effect from "effect/Effect";
|
|
9
9
|
import * as Layer from "effect/Layer";
|
|
10
10
|
import { Jmap } from "#apis";
|
|
11
|
-
import
|
|
11
|
+
import * as MailSync from "@dxos/plugin-inbox/MailSync";
|
|
12
12
|
import { JmapCredentials } from "#services";
|
|
13
13
|
import { AccessToken, Connection } from "@dxos/link";
|
|
14
14
|
import * as Mailbox from "@dxos/plugin-inbox/Mailbox";
|
|
15
15
|
import * as Trigger from "@dxos/compute/Trigger";
|
|
16
16
|
import * as SyncOptions from "@dxos/plugin-inbox/SyncOptions";
|
|
17
|
-
import * as FetchHttpClient from "effect/
|
|
17
|
+
import * as FetchHttpClient from "effect/http/FetchHttpClient";
|
|
18
18
|
var jmapCredentialForm = {
|
|
19
19
|
schema: Schema.Struct({
|
|
20
20
|
host: Schema.String.annotate({
|
|
@@ -38,8 +38,8 @@ var jmapCredentialForm = {
|
|
|
38
38
|
onValidate: ({ values }) => Effect.gen(function* () {
|
|
39
39
|
const host = values.host.trim();
|
|
40
40
|
const token = values.token.trim();
|
|
41
|
-
if (host.length === 0) return yield* Effect.fail(
|
|
42
|
-
if (token.length === 0) return yield* Effect.fail(
|
|
41
|
+
if (host.length === 0) return yield* Effect.fail(new JmapCredentialInvalidError({ message: "Server host is required." }));
|
|
42
|
+
if (token.length === 0) return yield* Effect.fail(new JmapCredentialInvalidError({ message: "API token is required." }));
|
|
43
43
|
yield* fetchSession(host, token);
|
|
44
44
|
}),
|
|
45
45
|
onSubmit: ({ values, connector }) => Effect.gen(function* () {
|
|
@@ -84,7 +84,7 @@ var buildJmapCredential = ({ host, email, token, session, connector }) => {
|
|
|
84
84
|
var fetchSession = (host, token) => Jmap.getSession.pipe(Effect.provide(Layer.mergeAll(FetchHttpClient.layer, JmapCredentials.fromValues({
|
|
85
85
|
host,
|
|
86
86
|
token
|
|
87
|
-
}))), Effect.mapError((error) => error instanceof JmapApiError && error.status === 401 ?
|
|
87
|
+
}))), Effect.mapError((error) => error instanceof JmapApiError && error.status === 401 ? new JmapCredentialInvalidError({ message: "The JMAP server rejected the token (401). Check the host and API token and try again." }) : error instanceof Error ? error : new JmapCredentialInvalidError({ message: String(error) })));
|
|
88
88
|
//#endregion
|
|
89
89
|
//#region src/capabilities/connector.ts
|
|
90
90
|
var connector_default = Capability.makeModule(Effect.fnUntraced(function* () {
|
|
@@ -98,9 +98,9 @@ var connector_default = Capability.makeModule(Effect.fnUntraced(function* () {
|
|
|
98
98
|
targetTypename: Type.getTypename(Mailbox.Mailbox),
|
|
99
99
|
materializeTarget: JmapOperation.MaterializeJmapTarget,
|
|
100
100
|
optionsSchema: SyncOptions.SyncOptions,
|
|
101
|
-
auto: MAIL_AUTO_SYNC,
|
|
102
|
-
trigger: Trigger.specTimer(MAIL_SYNC_CRON),
|
|
103
|
-
remote: MAIL_REMOTE_SYNC
|
|
101
|
+
auto: MailSync.MAIL_AUTO_SYNC,
|
|
102
|
+
trigger: Trigger.specTimer(MailSync.MAIL_SYNC_CRON),
|
|
103
|
+
remote: MailSync.MAIL_REMOTE_SYNC
|
|
104
104
|
}
|
|
105
105
|
}]);
|
|
106
106
|
}));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chunk-connector.mjs","names":[],"sources":["../../src/capabilities/credential-form.ts","../../src/capabilities/connector.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Effect from 'effect/Effect';\nimport * as
|
|
1
|
+
{"version":3,"file":"chunk-connector.mjs","names":[],"sources":["../../src/capabilities/credential-form.ts","../../src/capabilities/connector.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Effect from 'effect/Effect';\nimport * as FetchHttpClient from 'effect/http/FetchHttpClient';\nimport * as Layer from 'effect/Layer';\nimport * as Schema from 'effect/Schema';\n\nimport { Format, Obj, Ref } from '@dxos/echo';\nimport { AccessToken, Connection } from '@dxos/link';\nimport * as ConnectorSpec from '@dxos/plugin-connector/ConnectorSpec';\n\nimport { Jmap } from '#apis';\nimport { JmapCredentials } from '#services';\n\nimport { JMAP_DEFAULT_HOST } from '../constants.ts';\nimport { JmapApiError, JmapCredentialInvalidError } from '../errors.ts';\n\n/**\n * Manual-credential form for the JMAP connector. JMAP auth is a server-issued Bearer API token\n * (Fastmail: Settings → Privacy & Security → Integrations), outside any OAuth flow, so the host,\n * email, and token are collected directly.\n */\nconst JmapCredentialFormSchema = Schema.Struct({\n host: Schema.String.annotate({\n title: 'Server',\n description: 'JMAP server host. The session is discovered at https://<host>/.well-known/jmap.',\n }),\n email: Schema.String.annotate({\n title: 'Email',\n description: 'Your email address / username on the JMAP server.',\n }),\n token: Schema.String.pipe(Format.FormatAnnotation.set(Format.TypeFormat.Password)).annotate({\n title: 'API token',\n description: 'A JMAP API token, sent as a Bearer credential.',\n }),\n});\n\ntype JmapCredentialFormValues = Schema.Schema.Type<typeof JmapCredentialFormSchema>;\n\nexport const jmapCredentialForm: ConnectorSpec.CredentialForm<JmapCredentialFormValues> = {\n schema: JmapCredentialFormSchema,\n defaultValues: { host: JMAP_DEFAULT_HOST, email: '', token: '' },\n // Validate against the live session before the dialog closes so a wrong host/token fails inline\n // (with a clear 401 message) instead of creating a Connection that errors on every later sync.\n onValidate: ({ values }) =>\n Effect.gen(function* () {\n const host = values.host.trim();\n const token = values.token.trim();\n if (host.length === 0) {\n return yield* Effect.fail(new JmapCredentialInvalidError({ message: 'Server host is required.' }));\n }\n if (token.length === 0) {\n return yield* Effect.fail(new JmapCredentialInvalidError({ message: 'API token is required.' }));\n }\n yield* fetchSession(host, token);\n }),\n onSubmit: ({ values, connector }) =>\n Effect.gen(function* () {\n // Trim defensively: onValidate is optional and callers bypass it in tests.\n const host = values.host.trim();\n const email = values.email.trim();\n const token = values.token.trim();\n const session = yield* fetchSession(host, token);\n const { accessToken, connection } = buildJmapCredential({ host, email, token, session, connector });\n return { kind: 'complete' as const, accessToken, connection };\n }),\n};\n\n/**\n * Builds the `AccessToken` (source = host, account = form email or session username) and `Connection`\n * for a validated JMAP credential. Pure (no DB), so the construction is unit-testable.\n */\nexport const buildJmapCredential = ({\n host,\n email,\n token,\n session,\n connector,\n}: {\n host: string;\n email: string;\n token: string;\n session: Jmap.Session;\n connector: { id?: string; label?: string };\n}) => {\n const account = email.length > 0 ? email : session.username;\n const accessToken = Obj.make(AccessToken.AccessToken, {\n source: host,\n ...(account ? { account } : {}),\n token,\n });\n const connection = Connection.make({\n name: connector.label ?? 'JMAP',\n connectorId: connector.id,\n accessToken: Ref.make(accessToken),\n });\n return { accessToken, connection };\n};\n\n/** Discovers the JMAP session for the given host/token, surfacing a friendly message on 401. */\nconst fetchSession = (host: string, token: string) =>\n Jmap.getSession.pipe(\n Effect.provide(Layer.mergeAll(FetchHttpClient.layer, JmapCredentials.fromValues({ host, token }))),\n Effect.mapError((error) =>\n error instanceof JmapApiError && error.status === 401\n ? new JmapCredentialInvalidError({\n message: 'The JMAP server rejected the token (401). Check the host and API token and try again.',\n })\n : error instanceof Error\n ? error\n : new JmapCredentialInvalidError({ message: String(error) }),\n ),\n );\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Effect from 'effect/Effect';\n\nimport * as Capability from '@dxos/app-framework/Capability';\nimport * as Trigger from '@dxos/compute/Trigger';\nimport { Type } from '@dxos/echo';\nimport * as ConnectorSpec from '@dxos/plugin-connector/ConnectorSpec';\nimport * as Mailbox from '@dxos/plugin-inbox/Mailbox';\nimport * as MailSync from '@dxos/plugin-inbox/MailSync';\nimport * as SyncOptions from '@dxos/plugin-inbox/SyncOptions';\n\nimport { JmapOperation } from '#types';\n\nimport { JMAP_DEFAULT_HOST, JMAP_MAIL_CONNECTOR_ID } from '../constants.ts';\nimport { jmapCredentialForm } from './credential-form.ts';\n\nexport default Capability.makeModule(\n Effect.fnUntraced(function* () {\n return Capability.contribute(ConnectorSpec.Connector, [\n {\n id: JMAP_MAIL_CONNECTOR_ID,\n // Nominal default; the real `AccessToken.source` (host) is captured by the credential form.\n source: JMAP_DEFAULT_HOST,\n label: 'JMAP Mail',\n // Non-OAuth: host + email + Bearer API token, validated against the live session on submit.\n credentialForm: jmapCredentialForm,\n sync: {\n operation: JmapOperation.JmapSync,\n // What this connector binds — how `Mailbox` discovers it without naming JMAP.\n targetTypename: Type.getTypename(Mailbox.Mailbox),\n // Single-target connector (the account inbox): no `getTargets`. The coordinator calls\n // `materializeTarget` (no remoteTarget) to create the Mailbox, then binds.\n materializeTarget: JmapOperation.MaterializeJmapTarget,\n optionsSchema: SyncOptions.SyncOptions,\n auto: MailSync.MAIL_AUTO_SYNC,\n trigger: Trigger.specTimer(MailSync.MAIL_SYNC_CRON),\n remote: MailSync.MAIL_REMOTE_SYNC,\n },\n },\n ]);\n }),\n);\n"],"mappings":";;;;;;;;;;;;;;;;;AAyCA,IAAa,qBAA6E;CACxF,QAlB+B,OAAO,OAAO;EAC7C,MAAM,OAAO,OAAO,SAAS;GAC3B,OAAO;GACP,aAAa;EACf,CAAC;EACD,OAAO,OAAO,OAAO,SAAS;GAC5B,OAAO;GACP,aAAa;EACf,CAAC;EACD,OAAO,OAAO,OAAO,KAAK,OAAO,iBAAiB,IAAI,OAAO,WAAW,QAAQ,CAAC,CAAC,CAAC,SAAS;GAC1F,OAAO;GACP,aAAa;EACf,CAAC;CACH,CAKU;CACR,eAAe;EAAE,MAAM;EAAmB,OAAO;EAAI,OAAO;CAAG;CAG/D,aAAa,EAAE,aACb,OAAO,IAAI,aAAa;EACtB,MAAM,OAAO,OAAO,KAAK,KAAK;EAC9B,MAAM,QAAQ,OAAO,MAAM,KAAK;EAChC,IAAI,KAAK,WAAW,GAClB,OAAO,OAAO,OAAO,KAAK,IAAI,2BAA2B,EAAE,SAAS,2BAA2B,CAAC,CAAC;EAEnG,IAAI,MAAM,WAAW,GACnB,OAAO,OAAO,OAAO,KAAK,IAAI,2BAA2B,EAAE,SAAS,yBAAyB,CAAC,CAAC;EAEjG,OAAO,aAAa,MAAM,KAAK;CACjC,CAAC;CACH,WAAW,EAAE,QAAQ,gBACnB,OAAO,IAAI,aAAa;EAEtB,MAAM,OAAO,OAAO,KAAK,KAAK;EAC9B,MAAM,QAAQ,OAAO,MAAM,KAAK;EAChC,MAAM,QAAQ,OAAO,MAAM,KAAK;EAEhC,MAAM,EAAE,aAAa,eAAe,oBAAoB;GAAE;GAAM;GAAO;GAAO,gBADvD,aAAa,MAAM,KAAK;GACwC;EAAU,CAAC;EAClG,OAAO;GAAE,MAAM;GAAqB;GAAa;EAAW;CAC9D,CAAC;AACL;;;;;AAMA,IAAa,uBAAuB,EAClC,MACA,OACA,OACA,SACA,gBAOI;CACJ,MAAM,UAAU,MAAM,SAAS,IAAI,QAAQ,QAAQ;CACnD,MAAM,cAAc,IAAI,KAAK,YAAY,aAAa;EACpD,QAAQ;EACR,GAAI,UAAU,EAAE,QAAQ,IAAI,CAAC;EAC7B;CACF,CAAC;CAMD,OAAO;EAAE;EAAa,YALH,WAAW,KAAK;GACjC,MAAM,UAAU,SAAS;GACzB,aAAa,UAAU;GACvB,aAAa,IAAI,KAAK,WAAW;EACnC,CACsB;CAAW;AACnC;;AAGA,IAAM,gBAAgB,MAAc,UAClC,KAAK,WAAW,KACd,OAAO,QAAQ,MAAM,SAAS,gBAAgB,OAAO,gBAAgB,WAAW;CAAE;CAAM;AAAM,CAAC,CAAC,CAAC,GACjG,OAAO,UAAU,UACf,iBAAiB,gBAAgB,MAAM,WAAW,MAC9C,IAAI,2BAA2B,EAC7B,SAAS,wFACX,CAAC,IACD,iBAAiB,QACf,QACA,IAAI,2BAA2B,EAAE,SAAS,OAAO,KAAK,EAAE,CAAC,CACjE,CACF;;;AC/FF,IAAA,oBAAe,WAAW,WACxB,OAAO,WAAW,aAAa;CAC7B,OAAO,WAAW,WAAW,cAAc,WAAW,CACpD;EACE,IAAI;EAEJ,QAAQ;EACR,OAAO;EAEP,gBAAgB;EAChB,MAAM;GACJ,WAAW,cAAc;GAEzB,gBAAgB,KAAK,YAAY,QAAQ,OAAO;GAGhD,mBAAmB,cAAc;GACjC,eAAe,YAAY;GAC3B,MAAM,SAAS;GACf,SAAS,QAAQ,UAAU,SAAS,cAAc;GAClD,QAAQ,SAAS;EACnB;CACF,CACF,CAAC;AACH,CAAC,CACH"}
|
|
@@ -36,7 +36,9 @@ var JmapSendIdentityNotFoundError = class extends BaseError.extend("JmapSendIden
|
|
|
36
36
|
});
|
|
37
37
|
}
|
|
38
38
|
};
|
|
39
|
+
/** A JMAP credential form was submitted with a field missing or empty. */
|
|
40
|
+
var JmapCredentialInvalidError = class extends BaseError.extend("JmapCredentialInvalidError", "JMAP credentials are incomplete.") {};
|
|
39
41
|
//#endregion
|
|
40
|
-
export {
|
|
42
|
+
export { JmapSendMessageInvalidError as i, JmapCredentialInvalidError as n, JmapSendIdentityNotFoundError as r, JmapApiError as t };
|
|
41
43
|
|
|
42
44
|
//# sourceMappingURL=chunk-errors.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chunk-errors.mjs","names":[],"sources":["../../src/errors.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport { BaseError, type BaseErrorOptions } from '@dxos/errors';\n\n/**\n * JMAP request failed: a non-2xx HTTP status, a JMAP problem-details body, or a method-level\n * `[\"error\", { type, description }, id]` response. `status` carries the HTTP status (when the\n * failure is transport-level) and `type` the JMAP error type (when method-level) so callers can\n * recover with `Effect.catchTag` and distinguish auth (401) from other failures.\n */\nexport class JmapApiError extends BaseError.extend('JmapApiError', 'JMAP API request failed.') {\n constructor(\n public readonly status: number | undefined,\n public readonly detail: string,\n public readonly type?: string,\n options?: BaseErrorOptions,\n ) {\n super({ ...options, context: { ...(options?.context ?? {}), status, detail, type } });\n }\n}\n\n/** JMAP send payload missing required fields (`to` or body text). */\nexport class JmapSendMessageInvalidError extends BaseError.extend(\n 'JmapSendMessageInvalidError',\n 'Missing \"to\" or content in message.',\n) {}\n\n/** No JMAP identity permits the connection account as a `from` address, so the email cannot be sent. */\nexport class JmapSendIdentityNotFoundError extends BaseError.extend(\n 'JmapSendIdentityNotFoundError',\n 'No JMAP identity matches the connection account.',\n) {\n constructor(account: string | undefined, options?: Omit<BaseErrorOptions, 'context'>) {\n super({ context: { account }, ...options });\n }\n}\n"],"mappings":";;;;;;;;AAYA,IAAa,eAAb,cAAkC,UAAU,OAAO,gBAAgB,0BAA0B,CAAC,CAAC;CAE3E;CACA;CACA;CAHlB,YACE,QACA,QACA,MACA,SACA;EACA,MAAM;GAAE,GAAG;GAAS,SAAS;IAAE,GAAI,SAAS,WAAW,CAAC;IAAI;IAAQ;IAAQ;GAAK;EAAE,CAAC;EALpE,KAAA,SAAA;EACA,KAAA,SAAA;EACA,KAAA,OAAA;CAIlB;AACF;;AAGA,IAAa,8BAAb,cAAiD,UAAU,OACzD,+BACA,uCACF,CAAC,CAAC,CAAC;;AAGH,IAAa,gCAAb,cAAmD,UAAU,OAC3D,iCACA,kDACF,CAAC,CAAC;CACA,YAAY,SAA6B,SAA6C;EACpF,MAAM;GAAE,SAAS,EAAE,QAAQ;GAAG,GAAG;EAAQ,CAAC;CAC5C;AACF"}
|
|
1
|
+
{"version":3,"file":"chunk-errors.mjs","names":[],"sources":["../../src/errors.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport { BaseError, type BaseErrorOptions } from '@dxos/errors';\n\n/**\n * JMAP request failed: a non-2xx HTTP status, a JMAP problem-details body, or a method-level\n * `[\"error\", { type, description }, id]` response. `status` carries the HTTP status (when the\n * failure is transport-level) and `type` the JMAP error type (when method-level) so callers can\n * recover with `Effect.catchTag` and distinguish auth (401) from other failures.\n */\nexport class JmapApiError extends BaseError.extend('JmapApiError', 'JMAP API request failed.') {\n constructor(\n public readonly status: number | undefined,\n public readonly detail: string,\n public readonly type?: string,\n options?: BaseErrorOptions,\n ) {\n super({ ...options, context: { ...(options?.context ?? {}), status, detail, type } });\n }\n}\n\n/** JMAP send payload missing required fields (`to` or body text). */\nexport class JmapSendMessageInvalidError extends BaseError.extend(\n 'JmapSendMessageInvalidError',\n 'Missing \"to\" or content in message.',\n) {}\n\n/** No JMAP identity permits the connection account as a `from` address, so the email cannot be sent. */\nexport class JmapSendIdentityNotFoundError extends BaseError.extend(\n 'JmapSendIdentityNotFoundError',\n 'No JMAP identity matches the connection account.',\n) {\n constructor(account: string | undefined, options?: Omit<BaseErrorOptions, 'context'>) {\n super({ context: { account }, ...options });\n }\n}\n\n/** A JMAP credential form was submitted with a field missing or empty. */\nexport class JmapCredentialInvalidError extends BaseError.extend(\n 'JmapCredentialInvalidError',\n 'JMAP credentials are incomplete.',\n) {}\n"],"mappings":";;;;;;;;AAYA,IAAa,eAAb,cAAkC,UAAU,OAAO,gBAAgB,0BAA0B,CAAC,CAAC;CAE3E;CACA;CACA;CAHlB,YACE,QACA,QACA,MACA,SACA;EACA,MAAM;GAAE,GAAG;GAAS,SAAS;IAAE,GAAI,SAAS,WAAW,CAAC;IAAI;IAAQ;IAAQ;GAAK;EAAE,CAAC;EALpE,KAAA,SAAA;EACA,KAAA,SAAA;EACA,KAAA,OAAA;CAIlB;AACF;;AAGA,IAAa,8BAAb,cAAiD,UAAU,OACzD,+BACA,uCACF,CAAC,CAAC,CAAC;;AAGH,IAAa,gCAAb,cAAmD,UAAU,OAC3D,iCACA,kDACF,CAAC,CAAC;CACA,YAAY,SAA6B,SAA6C;EACpF,MAAM;GAAE,SAAS,EAAE,QAAQ;GAAG,GAAG;EAAQ,CAAC;CAC5C;AACF;;AAGA,IAAa,6BAAb,cAAgD,UAAU,OACxD,8BACA,kCACF,CAAC,CAAC,CAAC"}
|
|
@@ -3,7 +3,7 @@ import { JmapOperation } from "#types";
|
|
|
3
3
|
import { Database, Obj, Ref } from "@dxos/echo";
|
|
4
4
|
import * as Effect from "effect/Effect";
|
|
5
5
|
import * as Mailbox from "@dxos/plugin-inbox/Mailbox";
|
|
6
|
-
import
|
|
6
|
+
import * as ConnectorSync from "@dxos/app-toolkit/ConnectorSync";
|
|
7
7
|
//#region src/operations/mail/materialize/handler.ts
|
|
8
8
|
/**
|
|
9
9
|
* Eagerly materializes a local Mailbox so the sync cursor's target exists before the cursor is
|
|
@@ -14,7 +14,7 @@ import { SyncDatabaseMissingError } from "@dxos/app-toolkit";
|
|
|
14
14
|
var handler = JmapOperation.MaterializeJmapTarget.pipe(Operation.withHandler(Effect.fnUntraced(function* ({ connection }) {
|
|
15
15
|
const connectionObj = connection.target;
|
|
16
16
|
const db = connectionObj ? Obj.getDatabase(connectionObj) : void 0;
|
|
17
|
-
if (!connectionObj || !db) return yield* Effect.fail(new
|
|
17
|
+
if (!connectionObj || !db) return yield* Effect.fail(new ConnectorSync.DatabaseMissingError());
|
|
18
18
|
return yield* Effect.gen(function* () {
|
|
19
19
|
const name = (yield* Database.load(connectionObj.accessToken)).account ?? "Inbox";
|
|
20
20
|
const created = yield* Database.add(Mailbox.make({ name }));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chunk-handler.mjs","names":[],"sources":["../../src/operations/mail/materialize/handler.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Effect from 'effect/Effect';\n\nimport
|
|
1
|
+
{"version":3,"file":"chunk-handler.mjs","names":[],"sources":["../../src/operations/mail/materialize/handler.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Effect from 'effect/Effect';\n\nimport * as ConnectorSync from '@dxos/app-toolkit/ConnectorSync';\nimport * as Operation from '@dxos/compute/Operation';\nimport { Database, Obj, Ref } from '@dxos/echo';\nimport * as Mailbox from '@dxos/plugin-inbox/Mailbox';\n\nimport { JmapOperation } from '#types';\n\n/**\n * Eagerly materializes a local Mailbox so the sync cursor's target exists before the cursor is\n * created. JMAP is a single-target connector (the account inbox), so a fresh Mailbox is always\n * created; the connection's `accessToken.account` seeds the default name. Mirrors the Gmail\n * materialize-target.\n */\nconst handler: Operation.WithHandler<typeof JmapOperation.MaterializeJmapTarget> =\n JmapOperation.MaterializeJmapTarget.pipe(\n Operation.withHandler(\n Effect.fnUntraced(function* ({ connection }) {\n // The operation derives the db from the connection ref's target and provides\n // `Database.layer(db)` itself (composer's invoker is wired without a `databaseResolver`).\n const connectionObj = connection.target;\n const db = connectionObj ? Obj.getDatabase(connectionObj) : undefined;\n if (!connectionObj || !db) {\n return yield* Effect.fail(new ConnectorSync.DatabaseMissingError());\n }\n\n return yield* Effect.gen(function* () {\n const accessToken = yield* Database.load(connectionObj.accessToken);\n const name = accessToken.account ?? 'Inbox';\n const created = yield* Database.add(Mailbox.make({ name }));\n return { target: Ref.make(created) };\n }).pipe(Effect.provide(Database.layer(db)));\n }),\n ),\n );\n\nexport default handler;\n"],"mappings":";;;;;;;;;;;;;AAmBA,IAAM,UACJ,cAAc,sBAAsB,KAClC,UAAU,YACR,OAAO,WAAW,WAAW,EAAE,cAAc;CAG3C,MAAM,gBAAgB,WAAW;CACjC,MAAM,KAAK,gBAAgB,IAAI,YAAY,aAAa,IAAI,KAAA;CAC5D,IAAI,CAAC,iBAAiB,CAAC,IACrB,OAAO,OAAO,OAAO,KAAK,IAAI,cAAc,qBAAqB,CAAC;CAGpE,OAAO,OAAO,OAAO,IAAI,aAAa;EAEpC,MAAM,QAAO,OADc,SAAS,KAAK,cAAc,WAAW,EAAA,CACzC,WAAW;EACpC,MAAM,UAAU,OAAO,SAAS,IAAI,QAAQ,KAAK,EAAE,KAAK,CAAC,CAAC;EAC1D,OAAO,EAAE,QAAQ,IAAI,KAAK,OAAO,EAAE;CACrC,CAAC,CAAC,CAAC,KAAK,OAAO,QAAQ,SAAS,MAAM,EAAE,CAAC,CAAC;AAC5C,CAAC,CACH,CACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chunk-mail-send.mjs","names":[],"sources":["../../src/capabilities/mail-send.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Effect from 'effect/Effect';\n\nimport * as Capability from '@dxos/app-framework/Capability';\nimport * as InboxCapabilities from '@dxos/plugin-inbox/InboxCapabilities';\n\nimport { JmapOperation } from '#types';\n\nimport { JMAP_MAIL_CONNECTOR_ID } from '../constants';\n\n/** Routes a draft whose mailbox is bound to a JMAP connection to this provider's send operation. */\nexport default Capability.makeModule(\n Effect.fnUntraced(function* () {\n return Capability.contribute(InboxCapabilities.MailSendOperation, {\n connectorId: JMAP_MAIL_CONNECTOR_ID,\n getOperation: () => JmapOperation.JmapSend,\n });\n }),\n);\n"],"mappings":";;;;;;;AAcA,IAAA,oBAAe,WAAW,WACxB,OAAO,WAAW,aAAa;CAC7B,OAAO,WAAW,WAAW,kBAAkB,mBAAmB;EAChE,aAAa;EACb,oBAAoB,cAAc;CACpC,CAAC;AACH,CAAC,CACH"}
|
|
1
|
+
{"version":3,"file":"chunk-mail-send.mjs","names":[],"sources":["../../src/capabilities/mail-send.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Effect from 'effect/Effect';\n\nimport * as Capability from '@dxos/app-framework/Capability';\nimport * as InboxCapabilities from '@dxos/plugin-inbox/InboxCapabilities';\n\nimport { JmapOperation } from '#types';\n\nimport { JMAP_MAIL_CONNECTOR_ID } from '../constants.ts';\n\n/** Routes a draft whose mailbox is bound to a JMAP connection to this provider's send operation. */\nexport default Capability.makeModule(\n Effect.fnUntraced(function* () {\n return Capability.contribute(InboxCapabilities.MailSendOperation, {\n connectorId: JMAP_MAIL_CONNECTOR_ID,\n getOperation: () => JmapOperation.JmapSend,\n });\n }),\n);\n"],"mappings":";;;;;;;AAcA,IAAA,oBAAe,WAAW,WACxB,OAAO,WAAW,aAAa;CAC7B,OAAO,WAAW,WAAW,kBAAkB,mBAAmB;EAChE,aAAa;EACb,oBAAoB,cAAc;CACpC,CAAC;AACH,CAAC,CACH"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as Capability from "@dxos/app-framework/Capability";
|
|
2
|
+
import { JmapOperationHandlerSet } from "#operations";
|
|
2
3
|
import * as Effect from "effect/Effect";
|
|
3
4
|
import * as Capabilities from "@dxos/app-framework/Capabilities";
|
|
4
|
-
import { JmapOperationHandlerSet } from "#operations";
|
|
5
5
|
//#region src/capabilities/operation-handler.ts
|
|
6
6
|
var operation_handler_default = Capability.makeModule(Effect.fnUntraced(function* () {
|
|
7
7
|
return Capability.contribute(Capabilities.OperationHandler, JmapOperationHandlerSet.handlers);
|