@remit/api-openapi-types 0.0.80 → 0.0.81

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/package.json +4 -1
  2. package/types.d.ts +319 -264
package/package.json CHANGED
@@ -1,9 +1,12 @@
1
1
  {
2
2
  "name": "@remit/api-openapi-types",
3
- "version": "0.0.80",
3
+ "version": "0.0.81",
4
4
  "type": "module",
5
5
  "main": "types.d.ts",
6
6
  "types": "types.d.ts",
7
+ "dependencies": {
8
+ "openapi-client-axios": "^7.9.1"
9
+ },
7
10
  "license": "MIT",
8
11
  "publishConfig": {
9
12
  "access": "public"
package/types.d.ts CHANGED
@@ -53,6 +53,10 @@ writer can reach is a vocabulary that lies about what the field means.
53
53
  `MissingEnvelope` is absent for the same reason: see QuarantineFailureStage.
54
54
  */
55
55
  export type QuarantineFailureCode = "UnknownCharset" | "UnreadableBody";
56
+ /**
57
+ * The sync step a message failed at.
58
+ */
59
+ export type SyncWarningStage = "Header" | "Body";
56
60
  /**
57
61
  * Lifecycle state of an account configuration
58
62
  */
@@ -134,7 +138,7 @@ current enum emitter anyway, so the wire contract uses the bare form.
134
138
  */
135
139
  export type FilterMatchOperator = "And" | "Or";
136
140
  /**
137
- * Message attribute a FilterClause matches against — RFC 031's Tier 0 literal predicates plus the RFC 038 D2 additions (list membership and sender domain). Every member is matched vector-free at index time and in the back-apply corpus projection.
141
+ * Message attribute a FilterClause matches against — RFC 031's Tier 0 literal predicates plus the RFC 038 D2 additions (list membership and sender domain). Every member is matched at index time and in the back-apply corpus projection.
138
142
  */
139
143
  export type FilterClauseField = "From" | "Subject" | "HasWords" | "ListId" | "FromDomain";
140
144
  /**
@@ -220,10 +224,6 @@ explained to the user as a failed delete.
220
224
  * Actionable placement verdict — the direction Remit decided to move a message. `leave` is not represented: a left-in-place verdict means the placement sub-model is absent.
221
225
  */
222
226
  export type PlacementAction = "MoveToInbox" | "MoveToJunk";
223
- /**
224
- * Allowed chunk types that may be the best match for a semantic-search hit
225
- */
226
- export type SemanticSearchChunkType = "sender" | "recipient" | "subject" | "attachment" | "body" | "entities";
227
227
  /**
228
228
  * Status of an outbox message in the send queue
229
229
  */
@@ -348,6 +348,10 @@ distinguishable from a network failure without parsing prose.
348
348
  * Which piece of configuration a still-unbound folder reference belongs to. A mailbox id is regenerated by every discovery, so an imported file names folders by IMAP path and the binder writes the row once a path resolves.
349
349
  */
350
350
  export type ConfigImportRefKind = "FolderRole" | "MailboxOverride" | "FilterAction";
351
+ /**
352
+ * Whether sync still retries a warned message. Derived from stage and attempts, never stored.
353
+ */
354
+ export type SyncWarningState = "Retrying" | "GaveUp";
351
355
  /**
352
356
  * Explicit state engine for a pending placement-move marker (issue #1271, epic #1281). Recovery keys off this field, not control-flow inference: a redelivered/retried call drives a marker forward from whichever state it is actually in, rather than re-deriving intent by comparing the message's current location.
353
357
  */
@@ -931,13 +935,21 @@ away before its body was stored. That answer carries `details.messageId`.
931
935
  errorMessage?: string;
932
936
  }
933
937
  /**
934
- * Everything quarantined for the current user, newest first. The list is small by design — a mailbox with a growing quarantine list is a bug being reported, not a page to paginate.
938
+ * Everything quarantined for the current user, newest first, beside the sync warnings that have failed enough rounds to surface. The quarantine list is small by design — a mailbox with a growing quarantine list is a bug being reported, not a page to paginate.
935
939
  */
936
940
  export interface QuarantineListResponse {
937
941
  /**
938
942
  * Quarantined messages, newest first.
939
943
  */
940
944
  entries: QuarantineResponse[];
945
+ /**
946
+ * The 200 newest sync warnings that have failed at least BODY_SYNC_MAX_ATTEMPTS rounds, newest first. One failing server quirk writes a row per message, so the list is capped.
947
+ */
948
+ warnings: SyncWarningResponse[];
949
+ /**
950
+ * Every sync warning at or past the attempt threshold, counting those beyond the cap on `warnings`.
951
+ */
952
+ warningsTotal: number;
941
953
  }
942
954
  /**
943
955
  * A message the sync path could not apply, set aside so the mailbox cursor can
@@ -1162,6 +1174,93 @@ never from a raw content-type line — parameters carry `name=` and
1162
1174
  createdAt: number;
1163
1175
  updatedAt: number;
1164
1176
  }
1177
+ /**
1178
+ * A message that failed to sync and was not set aside (issue #1400).
1179
+
1180
+ A warning only observes: it never filters a uid out of a round or moves a
1181
+ cursor. Each failure raises `attempts` on one row, and the row is deleted
1182
+ when the message later syncs. Whether a row is retrying or has given up is
1183
+ derived from `stage` and `attempts`, never stored.
1184
+ */
1185
+ export interface SyncWarning {
1186
+ /**
1187
+ * Deterministic v5 identity derived from accountId, mailboxId, uidValidity, uid and stage.
1188
+ */
1189
+ syncWarningId: UUID;
1190
+ /**
1191
+ * Owning account configuration — the user.
1192
+ */
1193
+ accountConfigId: UUID;
1194
+ /**
1195
+ * Mail account the message arrived on.
1196
+ */
1197
+ accountId: UUID;
1198
+ /**
1199
+ * Mailbox the message arrived in.
1200
+ */
1201
+ mailboxId: UUID;
1202
+ /**
1203
+ * UIDVALIDITY of the mailbox when the message failed. Only uidValidity + uid names a message forever (RFC 9051 2.3.1.1).
1204
+ */
1205
+ uidValidity: number;
1206
+ /**
1207
+ * The IMAP uid that failed.
1208
+ */
1209
+ uid: number;
1210
+ /**
1211
+ * The sync step the message failed at.
1212
+ */
1213
+ stage: SyncWarningStage;
1214
+ /**
1215
+ * Rounds that failed on this message so far.
1216
+ */
1217
+ attempts: number;
1218
+ /**
1219
+ * Epoch millis of the first failure.
1220
+ */
1221
+ createdAt: number;
1222
+ }
1223
+ /**
1224
+ * One sync warning as the settings surface sees it.
1225
+ */
1226
+ export interface SyncWarningResponse {
1227
+ /**
1228
+ * Deterministic v5 identity derived from accountId, mailboxId, uidValidity, uid and stage.
1229
+ */
1230
+ syncWarningId: UUID;
1231
+ /**
1232
+ * Owning account configuration — the user.
1233
+ */
1234
+ accountConfigId: UUID;
1235
+ /**
1236
+ * Mail account the message arrived on.
1237
+ */
1238
+ accountId: UUID;
1239
+ /**
1240
+ * Mailbox the message arrived in.
1241
+ */
1242
+ mailboxId: UUID;
1243
+ /**
1244
+ * UIDVALIDITY of the mailbox when the message failed. Only uidValidity + uid names a message forever (RFC 9051 2.3.1.1).
1245
+ */
1246
+ uidValidity: number;
1247
+ /**
1248
+ * The IMAP uid that failed.
1249
+ */
1250
+ uid: number;
1251
+ /**
1252
+ * The sync step the message failed at.
1253
+ */
1254
+ stage: SyncWarningStage;
1255
+ /**
1256
+ * Rounds that failed on this message so far.
1257
+ */
1258
+ attempts: number;
1259
+ /**
1260
+ * Epoch millis of the first failure.
1261
+ */
1262
+ createdAt: number;
1263
+ }
1165
1264
  /**
1166
1265
  * Full configuration description including accounts
1167
1266
  */
@@ -1175,13 +1274,13 @@ never from a raw content-type line — parameters carry `name=` and
1175
1274
  */
1176
1275
  accounts: AccountResponse[];
1177
1276
  /**
1178
- * Absent unless a configuration import is still waiting on folders IMAP has not produced yet (#1021). Nothing polls a separate route for it.
1277
+ * The commit the serving build was made from, or `dev` for a build made outside CI and git
1179
1278
  */
1180
- pendingImport?: PendingConfigImport;
1279
+ buildCommit: string;
1181
1280
  /**
1182
- * Whether this instance stores a vector for every message — SEARCH_EMBEDDING_PROVIDER is anything but `off`. False is a setting an operator turns on (`remit semantic on`), not a failure: the Organize semantic widen and semantic (anchor) filters read stored vectors and have none, so they render an off state rather than an empty result. It rides the config read because it is a property of the deployment, not of a query (#1068).
1281
+ * Absent unless a configuration import is still waiting on folders IMAP has not produced yet (#1021). Nothing polls a separate route for it.
1183
1282
  */
1184
- semanticSearchEnabled: boolean;
1283
+ pendingImport?: PendingConfigImport;
1185
1284
  }
1186
1285
  /**
1187
1286
  * Configuration container for user accounts. Groups multiple IMAP accounts under a single user.
@@ -1989,6 +2088,16 @@ with `onExisting: merge` to upsert instead.
1989
2088
  */
1990
2089
  displayNameOverride?: String256;
1991
2090
  }
2091
+ /**
2092
+ * A page of an account's mailboxes.
2093
+ */
2094
+ export interface MailboxListResponse {
2095
+ /**
2096
+ * Opaque, server-minted cursor: absent means the first (or last) page, present means resume from here. Echo it back unchanged to fetch the next page. Every listing endpoint that accepts it rejects a token it cannot decode with 400 ValidationError rather than silently restarting from the first page (#136, #172).
2097
+ */
2098
+ continuationToken?: String800;
2099
+ items: MailboxResponse[];
2100
+ }
1992
2101
  /**
1993
2102
  * Input for creating a new mailbox
1994
2103
  */
@@ -2029,14 +2138,10 @@ with `onExisting: merge` to upsert instead.
2029
2138
  mailboxId: string | any;
2030
2139
  }
2031
2140
  /**
2032
- * A standing user rule that matches messages by literal clauses and/or a
2033
- semantic anchor (RFC 031, RFC 034). One row per **standing** filter —
2034
- `Standing` or `Temporary` scope only. The one-time "just these" / "all like
2035
- these" batch actions never create one (RFC 034 recap).
2036
-
2037
- Kept lean: the semantic anchor payload lives on the sibling `FilterAnchor`
2038
- row (RFC 034 Decision 2.3) so listing/evaluating filters never pulls vector
2039
- data through `byAccountAndState`.
2141
+ * A standing user rule that matches messages by literal clauses (RFC 031,
2142
+ RFC 034). One row per **standing** filter — `Standing` or `Temporary` scope
2143
+ only. The one-time "just these" / "all like these" batch actions never
2144
+ create one (RFC 034 recap).
2040
2145
  */
2041
2146
  export interface Filter {
2042
2147
  /**
@@ -2052,7 +2157,7 @@ data through `byAccountAndState`.
2052
2157
  */
2053
2158
  name: String256;
2054
2159
  /**
2055
- * Standing (permanent) or Temporary (expires). Governs whether expiresAt/ttl are present (RFC 034 Decision 1). Mutable on update (reader #266): switching scope re-derives ttl and re-evaluates state from expiresAt, and bumps ruleChangedAt so a lapsed filter's back-application can be offered again. The semantic anchor stays immutable regardless — repointing it would silently change what a saved filter matches with nothing visible changing, which deserves a new filter instead.
2160
+ * Standing (permanent) or Temporary (expires). Governs whether expiresAt/ttl are present (RFC 034 Decision 1). Mutable on update (reader #266): switching scope re-derives ttl and re-evaluates state from expiresAt, and bumps ruleChangedAt so a lapsed filter's back-application can be offered again.
2056
2161
  */
2057
2162
  scope: FilterScope;
2058
2163
  /**
@@ -2071,24 +2176,20 @@ data through `byAccountAndState`.
2071
2176
  * Why this filter is Disabled; `None` whenever state is not Disabled. Written together with state, never on its own: turning a filter on clears it.
2072
2177
  */
2073
2178
  disabledReason: FilterDisabledReason;
2074
- /**
2075
- * Whether a sibling FilterAnchor row exists for this filter (RFC 034 Decision 2.3). Lets the index-time worker skip the FilterAnchor `get` entirely for purely-literal filters instead of probing for a row that may not exist.
2076
- */
2077
- hasAnchor: boolean;
2078
2179
  /**
2079
2180
  * Epoch seconds, written whenever the predicate, the action, the scope, or the expiry changes (reader #266) — never on a cosmetic rename. This is the broad "the user asserted something new about this rule" signal the settings UI uses to decide whether to re-offer a lapsed filter's back-application. It is deliberately NOT the precedence signal for the exclusive move action — see actionChangedAt for that (RFC 034 Decision 3.2, reader #384). Distinct from ElectroDB's own updatedAt, which bumps on any write.
2080
2181
  */
2081
2182
  ruleChangedAt: number;
2082
2183
  /**
2083
- * Epoch seconds, written only when the predicate (literalClauses, hasAnchor) or the action (actionLabelId, actionMailboxId) changes — never on scope, expiresAt, or a cosmetic rename. Backs most-recently-changed-filter-wins precedence for the exclusive move action (RFC 034 Decision 3.2). Split out from ruleChangedAt (reader #384): extending a filter's expiry or flipping its scope changes its lifecycle, not what it matches or does, so it must not promote the filter to move-winner.
2184
+ * Epoch seconds, written only when the predicate (literalClauses) or the action (actionLabelId, actionMailboxId) changes — never on scope, expiresAt, or a cosmetic rename. Backs most-recently-changed-filter-wins precedence for the exclusive move action (RFC 034 Decision 3.2). Split out from ruleChangedAt (reader #384): extending a filter's expiry or flipping its scope changes its lifecycle, not what it matches or does, so it must not promote the filter to move-winner.
2084
2185
  */
2085
2186
  actionChangedAt: number;
2086
2187
  /**
2087
- * How literalClauses combine. Meaningless when literalClauses is empty.
2188
+ * How literalClauses combine.
2088
2189
  */
2089
2190
  matchOperator: FilterMatchOperator;
2090
2191
  /**
2091
- * Literal from/subject/has-words predicate clauses (RFC 031). Empty when the filter relies solely on its semantic anchor (see hasAnchor).
2192
+ * Literal from/subject/has-words predicate clauses (RFC 031). A filter carries at least one.
2092
2193
  */
2093
2194
  literalClauses: FilterClause[];
2094
2195
  /**
@@ -2132,7 +2233,7 @@ data through `byAccountAndState`.
2132
2233
  */
2133
2234
  name: String256;
2134
2235
  /**
2135
- * Standing (permanent) or Temporary (expires). Governs whether expiresAt/ttl are present (RFC 034 Decision 1). Mutable on update (reader #266): switching scope re-derives ttl and re-evaluates state from expiresAt, and bumps ruleChangedAt so a lapsed filter's back-application can be offered again. The semantic anchor stays immutable regardless — repointing it would silently change what a saved filter matches with nothing visible changing, which deserves a new filter instead.
2236
+ * Standing (permanent) or Temporary (expires). Governs whether expiresAt/ttl are present (RFC 034 Decision 1). Mutable on update (reader #266): switching scope re-derives ttl and re-evaluates state from expiresAt, and bumps ruleChangedAt so a lapsed filter's back-application can be offered again.
2136
2237
  */
2137
2238
  scope: FilterScope;
2138
2239
  /**
@@ -2147,24 +2248,20 @@ data through `byAccountAndState`.
2147
2248
  * Why this filter is Disabled; `None` whenever state is not Disabled. Written together with state, never on its own: turning a filter on clears it.
2148
2249
  */
2149
2250
  disabledReason: FilterDisabledReason;
2150
- /**
2151
- * Whether a sibling FilterAnchor row exists for this filter (RFC 034 Decision 2.3). Lets the index-time worker skip the FilterAnchor `get` entirely for purely-literal filters instead of probing for a row that may not exist.
2152
- */
2153
- hasAnchor: boolean;
2154
2251
  /**
2155
2252
  * Epoch seconds, written whenever the predicate, the action, the scope, or the expiry changes (reader #266) — never on a cosmetic rename. This is the broad "the user asserted something new about this rule" signal the settings UI uses to decide whether to re-offer a lapsed filter's back-application. It is deliberately NOT the precedence signal for the exclusive move action — see actionChangedAt for that (RFC 034 Decision 3.2, reader #384). Distinct from ElectroDB's own updatedAt, which bumps on any write.
2156
2253
  */
2157
2254
  ruleChangedAt: number;
2158
2255
  /**
2159
- * Epoch seconds, written only when the predicate (literalClauses, hasAnchor) or the action (actionLabelId, actionMailboxId) changes — never on scope, expiresAt, or a cosmetic rename. Backs most-recently-changed-filter-wins precedence for the exclusive move action (RFC 034 Decision 3.2). Split out from ruleChangedAt (reader #384): extending a filter's expiry or flipping its scope changes its lifecycle, not what it matches or does, so it must not promote the filter to move-winner.
2256
+ * Epoch seconds, written only when the predicate (literalClauses) or the action (actionLabelId, actionMailboxId) changes — never on scope, expiresAt, or a cosmetic rename. Backs most-recently-changed-filter-wins precedence for the exclusive move action (RFC 034 Decision 3.2). Split out from ruleChangedAt (reader #384): extending a filter's expiry or flipping its scope changes its lifecycle, not what it matches or does, so it must not promote the filter to move-winner.
2160
2257
  */
2161
2258
  actionChangedAt: number;
2162
2259
  /**
2163
- * How literalClauses combine. Meaningless when literalClauses is empty.
2260
+ * How literalClauses combine.
2164
2261
  */
2165
2262
  matchOperator: FilterMatchOperator;
2166
2263
  /**
2167
- * Literal from/subject/has-words predicate clauses (RFC 031). Empty when the filter relies solely on its semantic anchor (see hasAnchor).
2264
+ * Literal from/subject/has-words predicate clauses (RFC 031). A filter carries at least one.
2168
2265
  */
2169
2266
  literalClauses: FilterClause[];
2170
2267
  /**
@@ -2181,12 +2278,8 @@ data through `byAccountAndState`.
2181
2278
  /**
2182
2279
  * Input for creating a filter (RFC 034). `ttl` is omitted — it is derived
2183
2280
  server-side from `expiresAt` when `scope` is `Temporary` (RFC 034 Decision
2184
- 1.3), never client-supplied. `state`, `hasAnchor`, `ruleChangedAt`, and
2185
- `filterId` are all server-derived and excluded by their Read-only visibility.
2186
-
2187
- When `anchorMessageId` is set, the server builds and persists the filter's
2188
- semantic anchor from that message's indexed vectors (RFC 034 Decision 2) and
2189
- sets `hasAnchor`. Absent for a purely-literal filter.
2281
+ 1.3), never client-supplied. `state`, `ruleChangedAt`, and `filterId` are
2282
+ all server-derived and excluded by their Read-only visibility.
2190
2283
  */
2191
2284
  export interface CreateFilterInput {
2192
2285
  /**
@@ -2194,7 +2287,7 @@ sets `hasAnchor`. Absent for a purely-literal filter.
2194
2287
  */
2195
2288
  name: String256;
2196
2289
  /**
2197
- * Standing (permanent) or Temporary (expires). Governs whether expiresAt/ttl are present (RFC 034 Decision 1). Mutable on update (reader #266): switching scope re-derives ttl and re-evaluates state from expiresAt, and bumps ruleChangedAt so a lapsed filter's back-application can be offered again. The semantic anchor stays immutable regardless — repointing it would silently change what a saved filter matches with nothing visible changing, which deserves a new filter instead.
2290
+ * Standing (permanent) or Temporary (expires). Governs whether expiresAt/ttl are present (RFC 034 Decision 1). Mutable on update (reader #266): switching scope re-derives ttl and re-evaluates state from expiresAt, and bumps ruleChangedAt so a lapsed filter's back-application can be offered again.
2198
2291
  */
2199
2292
  scope: FilterScope;
2200
2293
  /**
@@ -2202,11 +2295,11 @@ sets `hasAnchor`. Absent for a purely-literal filter.
2202
2295
  */
2203
2296
  expiresAt?: string;
2204
2297
  /**
2205
- * How literalClauses combine. Meaningless when literalClauses is empty.
2298
+ * How literalClauses combine.
2206
2299
  */
2207
2300
  matchOperator: FilterMatchOperator;
2208
2301
  /**
2209
- * Literal from/subject/has-words predicate clauses (RFC 031). Empty when the filter relies solely on its semantic anchor (see hasAnchor).
2302
+ * Literal from/subject/has-words predicate clauses (RFC 031). A filter carries at least one.
2210
2303
  */
2211
2304
  literalClauses: FilterClause[];
2212
2305
  /**
@@ -2217,10 +2310,6 @@ sets `hasAnchor`. Absent for a purely-literal filter.
2217
2310
  * Mailbox matched messages are moved into — exclusive action, since a message lives in exactly one mailbox (RFC 034 Decision 3.1). On conflict between filters, the one with the latest actionChangedAt wins. `"None"` means no move action.
2218
2311
  */
2219
2312
  actionMailboxId: string;
2220
- /**
2221
- * Anchor message for a semantic filter — provenance for the persisted anchor the server builds at save time (RFC 034 Decision 2.1). Absent for a purely-literal filter.
2222
- */
2223
- anchorMessageId?: UUID;
2224
2313
  }
2225
2314
  /**
2226
2315
  * Response body for POST /accounts/{accountId}/filters: the created filter, plus the back-apply job that runs it over the inbox.
@@ -2239,7 +2328,7 @@ sets `hasAnchor`. Absent for a purely-literal filter.
2239
2328
  */
2240
2329
  name: String256;
2241
2330
  /**
2242
- * Standing (permanent) or Temporary (expires). Governs whether expiresAt/ttl are present (RFC 034 Decision 1). Mutable on update (reader #266): switching scope re-derives ttl and re-evaluates state from expiresAt, and bumps ruleChangedAt so a lapsed filter's back-application can be offered again. The semantic anchor stays immutable regardless — repointing it would silently change what a saved filter matches with nothing visible changing, which deserves a new filter instead.
2331
+ * Standing (permanent) or Temporary (expires). Governs whether expiresAt/ttl are present (RFC 034 Decision 1). Mutable on update (reader #266): switching scope re-derives ttl and re-evaluates state from expiresAt, and bumps ruleChangedAt so a lapsed filter's back-application can be offered again.
2243
2332
  */
2244
2333
  scope: FilterScope;
2245
2334
  /**
@@ -2254,24 +2343,20 @@ sets `hasAnchor`. Absent for a purely-literal filter.
2254
2343
  * Why this filter is Disabled; `None` whenever state is not Disabled. Written together with state, never on its own: turning a filter on clears it.
2255
2344
  */
2256
2345
  disabledReason: FilterDisabledReason;
2257
- /**
2258
- * Whether a sibling FilterAnchor row exists for this filter (RFC 034 Decision 2.3). Lets the index-time worker skip the FilterAnchor `get` entirely for purely-literal filters instead of probing for a row that may not exist.
2259
- */
2260
- hasAnchor: boolean;
2261
2346
  /**
2262
2347
  * Epoch seconds, written whenever the predicate, the action, the scope, or the expiry changes (reader #266) — never on a cosmetic rename. This is the broad "the user asserted something new about this rule" signal the settings UI uses to decide whether to re-offer a lapsed filter's back-application. It is deliberately NOT the precedence signal for the exclusive move action — see actionChangedAt for that (RFC 034 Decision 3.2, reader #384). Distinct from ElectroDB's own updatedAt, which bumps on any write.
2263
2348
  */
2264
2349
  ruleChangedAt: number;
2265
2350
  /**
2266
- * Epoch seconds, written only when the predicate (literalClauses, hasAnchor) or the action (actionLabelId, actionMailboxId) changes — never on scope, expiresAt, or a cosmetic rename. Backs most-recently-changed-filter-wins precedence for the exclusive move action (RFC 034 Decision 3.2). Split out from ruleChangedAt (reader #384): extending a filter's expiry or flipping its scope changes its lifecycle, not what it matches or does, so it must not promote the filter to move-winner.
2351
+ * Epoch seconds, written only when the predicate (literalClauses) or the action (actionLabelId, actionMailboxId) changes — never on scope, expiresAt, or a cosmetic rename. Backs most-recently-changed-filter-wins precedence for the exclusive move action (RFC 034 Decision 3.2). Split out from ruleChangedAt (reader #384): extending a filter's expiry or flipping its scope changes its lifecycle, not what it matches or does, so it must not promote the filter to move-winner.
2267
2352
  */
2268
2353
  actionChangedAt: number;
2269
2354
  /**
2270
- * How literalClauses combine. Meaningless when literalClauses is empty.
2355
+ * How literalClauses combine.
2271
2356
  */
2272
2357
  matchOperator: FilterMatchOperator;
2273
2358
  /**
2274
- * Literal from/subject/has-words predicate clauses (RFC 031). Empty when the filter relies solely on its semantic anchor (see hasAnchor).
2359
+ * Literal from/subject/has-words predicate clauses (RFC 031). A filter carries at least one.
2275
2360
  */
2276
2361
  literalClauses: FilterClause[];
2277
2362
  /**
@@ -2293,7 +2378,7 @@ sets `hasAnchor`. Absent for a purely-literal filter.
2293
2378
  * Input for updating a filter (RFC 034, reader #266). The name, predicate,
2294
2379
  action, scope, and expiresAt are all updatable; `ttl` is always
2295
2380
  server-derived from `scope`/`expiresAt`, never client-supplied, and
2296
- `disabledReason`/`hasAnchor`/`ruleChangedAt`/`actionChangedAt`/`filterId` are
2381
+ `disabledReason`/`ruleChangedAt`/`actionChangedAt`/`filterId` are
2297
2382
  server-derived too. `state` takes `Active` or `Disabled`: the user turns a
2298
2383
  filter off or back on, and turning it on clears `disabledReason`. `Expired`
2299
2384
  is refused; the expiry is set through `scope`/`expiresAt`. A patch touching the predicate, the action, `scope`, or
@@ -2302,12 +2387,6 @@ Decision 3.2, reader #266). Only a patch touching the predicate or the
2302
2387
  action bumps `actionChangedAt`, the narrower signal exclusive-move
2303
2388
  precedence reads (reader #384) — a scope/expiresAt-only edit leaves it
2304
2389
  untouched.
2305
-
2306
- The semantic anchor has no field here at all — it is set once, from
2307
- `anchorMessageId`, only on `CreateFilterInput`. Repointing an anchor would
2308
- silently change what a saved filter matches with nothing visible changing;
2309
- that deserves a new filter, so the server rejects any attempt to smuggle an
2310
- anchor change through this body (reader #266).
2311
2390
  */
2312
2391
  export interface UpdateFilterInput {
2313
2392
  /**
@@ -2315,7 +2394,7 @@ anchor change through this body (reader #266).
2315
2394
  */
2316
2395
  name: String256;
2317
2396
  /**
2318
- * Standing (permanent) or Temporary (expires). Governs whether expiresAt/ttl are present (RFC 034 Decision 1). Mutable on update (reader #266): switching scope re-derives ttl and re-evaluates state from expiresAt, and bumps ruleChangedAt so a lapsed filter's back-application can be offered again. The semantic anchor stays immutable regardless — repointing it would silently change what a saved filter matches with nothing visible changing, which deserves a new filter instead.
2397
+ * Standing (permanent) or Temporary (expires). Governs whether expiresAt/ttl are present (RFC 034 Decision 1). Mutable on update (reader #266): switching scope re-derives ttl and re-evaluates state from expiresAt, and bumps ruleChangedAt so a lapsed filter's back-application can be offered again.
2319
2398
  */
2320
2399
  scope: FilterScope;
2321
2400
  /**
@@ -2327,11 +2406,11 @@ anchor change through this body (reader #266).
2327
2406
  */
2328
2407
  state: FilterState;
2329
2408
  /**
2330
- * How literalClauses combine. Meaningless when literalClauses is empty.
2409
+ * How literalClauses combine.
2331
2410
  */
2332
2411
  matchOperator: FilterMatchOperator;
2333
2412
  /**
2334
- * Literal from/subject/has-words predicate clauses (RFC 031). Empty when the filter relies solely on its semantic anchor (see hasAnchor).
2413
+ * Literal from/subject/has-words predicate clauses (RFC 031). A filter carries at least one.
2335
2414
  */
2336
2415
  literalClauses: FilterClause[];
2337
2416
  /**
@@ -2427,30 +2506,21 @@ anchor change through this body (reader #266).
2427
2506
  * The predicate + action for a one-time "all like these" back-apply (RFC 034
2428
2507
  recap, #1278). A distinct model, deliberately NOT a Filter: it carries no
2429
2508
  `scope`, `expiresAt`, or `name`, so it structurally cannot create a standing
2430
- rule. The anchor is derived transiently from `anchorMessageId`'s existing chunk
2431
- vectors at match time and never persisted as a FilterAnchor row.
2509
+ rule.
2432
2510
  */
2433
2511
  export interface OrganizeInput {
2434
2512
  /**
2435
- * Back-apply this standing filter instead of the predicate in this body. The server reads the filter's persisted predicate, action and FilterAnchor, runs the pass over the inbox, and skips a move another active filter outranks, as index time does. The predicate and action fields of this body are ignored when it is set.
2513
+ * Back-apply this standing filter instead of the predicate in this body. The server reads the filter's persisted predicate and action, runs the pass over the inbox, and skips a move another active filter outranks, as index time does. The predicate and action fields of this body are ignored when it is set.
2436
2514
  */
2437
2515
  filterId?: UUID;
2438
- /**
2439
- * Anchor message for the semantic half — "all like this one". Absent for a purely-literal back-apply. The anchor vector is pooled transiently from this message's indexed chunk vectors and never written to a FilterAnchor row.
2440
- */
2441
- anchorMessageId?: UUID;
2442
2516
  /**
2443
2517
  * How literalClauses combine. Meaningless when literalClauses is empty.
2444
2518
  */
2445
2519
  matchOperator: FilterMatchOperator;
2446
2520
  /**
2447
- * Literal from/subject/has-words clauses (RFC 031), reusing the Filter predicate shape. Empty when the back-apply relies solely on the semantic anchor.
2521
+ * Literal from/subject/has-words clauses (RFC 031), reusing the Filter predicate shape.
2448
2522
  */
2449
2523
  literalClauses: FilterClause[];
2450
- /**
2451
- * Cosine cut-off for the semantic match. Absent uses the server default (the same threshold the index-time filter pipeline applies).
2452
- */
2453
- similarityThreshold?: number;
2454
2524
  /**
2455
2525
  * Label applied to every matching message — additive action (RFC 034 Decision 3.1). The `"None"` sentinel means no label action.
2456
2526
  */
@@ -2486,14 +2556,6 @@ vectors at match time and never persisted as a FilterAnchor row.
2486
2556
  * Ids of the matching messages, bounded to the same cap the apply pass uses
2487
2557
  */
2488
2558
  messageIds: string[];
2489
- /**
2490
- * True when the semantic widen could not run because this deployment ships no vector pipeline (self-host without sqlite-vec / the embedding model). The matched set is then the literal matches only, or empty for an anchor-only predicate; literal search is unaffected. Absent on deployments where the widen ran.
2491
- */
2492
- semanticUnavailable?: boolean;
2493
- /**
2494
- * True when the widen ran but this account's semantic index held nothing to answer with — no vectors at all, or none yet for the anchor message. A zero count is then a fact about the index, which is still filling, rather than about the rule. Absent when the index answered.
2495
- */
2496
- semanticIndexEmpty?: boolean;
2497
2559
  }
2498
2560
  /**
2499
2561
  * An async "all like these" back-apply job (RFC 034 recap, #1278). Modeled on
@@ -2502,7 +2564,7 @@ to Running, then to Complete/Failed, self-reaping via the table-wide `ttl`.
2502
2564
 
2503
2565
  The predicate + action are snapshotted onto the row (the same fields as
2504
2566
  OrganizeInput) so the worker runs exactly what was requested. This job never
2505
- writes a Filter or FilterAnchor row — it is a single batch pass, nothing
2567
+ writes a Filter row — it is a single batch pass, nothing
2506
2568
  standing to persist.
2507
2569
  */
2508
2570
  export interface OrganizeJobRequest {
@@ -2526,10 +2588,6 @@ standing to persist.
2526
2588
  * The standing filter this job back-applies, or the `"None"` sentinel for an "all like these" pass. A sentinel, not an optional field, so the persisted entity has no optional attributes (RFC 032).
2527
2589
  */
2528
2590
  filterId: string;
2529
- /**
2530
- * Snapshot of the anchor message id, or the `"None"` sentinel for a purely-literal back-apply. A sentinel, not an optional field, so the persisted entity has no optional attributes (RFC 032).
2531
- */
2532
- anchorMessageId: string;
2533
2591
  /**
2534
2592
  * Snapshot of how literalClauses combine
2535
2593
  */
@@ -2538,10 +2596,6 @@ standing to persist.
2538
2596
  * Snapshot of the literal predicate clauses
2539
2597
  */
2540
2598
  literalClauses: FilterClause[];
2541
- /**
2542
- * Snapshot of the semantic cut-off applied for this run
2543
- */
2544
- similarityThreshold: number;
2545
2599
  /**
2546
2600
  * Snapshot of the additive label action, or `"None"`
2547
2601
  */
@@ -2603,10 +2657,6 @@ standing to persist.
2603
2657
  * The standing filter this job back-applies, or the `"None"` sentinel for an "all like these" pass. A sentinel, not an optional field, so the persisted entity has no optional attributes (RFC 032).
2604
2658
  */
2605
2659
  filterId: string;
2606
- /**
2607
- * Snapshot of the anchor message id, or the `"None"` sentinel for a purely-literal back-apply. A sentinel, not an optional field, so the persisted entity has no optional attributes (RFC 032).
2608
- */
2609
- anchorMessageId: string;
2610
2660
  /**
2611
2661
  * Snapshot of how literalClauses combine
2612
2662
  */
@@ -2615,10 +2665,6 @@ standing to persist.
2615
2665
  * Snapshot of the literal predicate clauses
2616
2666
  */
2617
2667
  literalClauses: FilterClause[];
2618
- /**
2619
- * Snapshot of the semantic cut-off applied for this run
2620
- */
2621
- similarityThreshold: number;
2622
2668
  /**
2623
2669
  * Snapshot of the additive label action, or `"None"`
2624
2670
  */
@@ -3670,7 +3716,7 @@ asking "is this slot free" never has to do the merging itself.
3670
3716
  */
3671
3717
  subject?: string;
3672
3718
  /**
3673
- * Normalized `List-Id` header value (bracketed identifier, case-folded), denormalized at body-sync so the back-apply corpus projection can match a `ListId` clause vector-free. Absent when the message carries no `List-Id` header or was body-synced before this field existed.
3719
+ * Normalized `List-Id` header value (bracketed identifier, case-folded), denormalized at body-sync so the back-apply corpus projection can match a `ListId` clause. Absent when the message carries no `List-Id` header or was body-synced before this field existed.
3674
3720
  */
3675
3721
  listId?: String256;
3676
3722
  /**
@@ -3906,6 +3952,16 @@ asking "is this slot free" never has to do the merging itself.
3906
3952
  */
3907
3953
  reportedAt: number;
3908
3954
  }
3955
+ /**
3956
+ * A page of thread messages.
3957
+ */
3958
+ export interface ThreadMessageListResponse {
3959
+ /**
3960
+ * Opaque, server-minted cursor: absent means the first (or last) page, present means resume from here. Echo it back unchanged to fetch the next page. Every listing endpoint that accepts it rejects a token it cannot decode with 400 ValidationError rather than silently restarting from the first page (#136, #172).
3961
+ */
3962
+ continuationToken?: String800;
3963
+ items: ThreadMessageResponse[];
3964
+ }
3909
3965
  /**
3910
3966
  * Aggregate response for the filterable thread listings — `searchThreads` and
3911
3967
  `listAllThreads`. Carries the matching rows (`items`), a pagination
@@ -3950,47 +4006,6 @@ page length presented as a total. A client with no number renders none.
3950
4006
  */
3951
4007
  count?: number;
3952
4008
  }
3953
- /**
3954
- * A single semantic-search hit. Display fields (fromName, subject, sentDate) are denormalized at index time and present for messages indexed after this feature was deployed. Older entries may omit them; clients should render a fallback when absent.
3955
- */
3956
- export interface SemanticSearchResult {
3957
- /**
3958
- * Matched message id
3959
- */
3960
- messageId: UUID;
3961
- /**
3962
- * Thread id the matched message belongs to
3963
- */
3964
- threadId: UUID;
3965
- /**
3966
- * Cosine similarity (or backend-equivalent) of the best matching chunk for this message; higher is more relevant
3967
- */
3968
- score: number;
3969
- /**
3970
- * Chunk type that produced the best match for this message
3971
- */
3972
- matchedChunkType: SemanticSearchChunkType;
3973
- /**
3974
- * All mailbox ids the matched message currently lives in
3975
- */
3976
- mailboxIds: UUID[];
3977
- /**
3978
- * Display name of the sender (From header). Present for messages indexed after display-field enrichment was deployed.
3979
- */
3980
- fromName?: string;
3981
- /**
3982
- * Message subject. Present for messages indexed after display-field enrichment was deployed.
3983
- */
3984
- subject?: string;
3985
- /**
3986
- * Sent date as Unix epoch seconds. Present for messages indexed after display-field enrichment was deployed.
3987
- */
3988
- sentDate?: number;
3989
- /**
3990
- * Header-derived category of the matched message. Present for messages indexed after category enrichment was deployed; older entries omit it.
3991
- */
3992
- category?: MessageCategory;
3993
- }
3994
4009
  /**
3995
4010
  * Input for creating an outbox message
3996
4011
  */
@@ -4302,6 +4317,16 @@ garbage, which is the only thing the sweep needs to know.
4302
4317
  */
4303
4318
  contentUrl: string;
4304
4319
  }
4320
+ /**
4321
+ * A page of the current account's outbox messages.
4322
+ */
4323
+ export interface OutboxMessageListResponse {
4324
+ /**
4325
+ * Opaque, server-minted cursor: absent means the first (or last) page, present means resume from here. Echo it back unchanged to fetch the next page. Every listing endpoint that accepts it rejects a token it cannot decode with 400 ValidationError rather than silently restarting from the first page (#136, #172).
4326
+ */
4327
+ continuationToken?: String800;
4328
+ items: OutboxMessageResponse[];
4329
+ }
4305
4330
  /**
4306
4331
  * Input for updating a draft outbox message
4307
4332
  */
@@ -4846,7 +4871,7 @@ either way and cannot tell which it received.
4846
4871
  /**
4847
4872
  * Core message entity. The combination of Mailbox.uidValidity + Message.uid uniquely identifies a message forever per RFC 9051 Section 2.3.1.1.
4848
4873
  */
4849
- export interface Message {
4874
+ export interface MessageRecord {
4850
4875
  /**
4851
4876
  * Primary identifier (internal UUID)
4852
4877
  */
@@ -4871,10 +4896,6 @@ either way and cannot tell which it received.
4871
4896
  * Server receipt timestamp (INTERNALDATE)
4872
4897
  */
4873
4898
  internalDate: number;
4874
- /**
4875
- * Message-ID header value for quick reference
4876
- */
4877
- messageIdHeader?: string;
4878
4899
  /**
4879
4900
  * Reference to parsed envelope data
4880
4901
  */
@@ -5043,9 +5064,9 @@ either way and cannot tell which it received.
5043
5064
  decidedAt: number;
5044
5065
  }
5045
5066
  /**
5046
- * Core message metadata for API responses
5067
+ * Core message entity as the API carries it: the stored row plus the Message-ID header, which is stored on the message's thread row.
5047
5068
  */
5048
- export interface MessageSummaryResponse {
5069
+ export interface Message {
5049
5070
  /**
5050
5071
  * Primary identifier (internal UUID)
5051
5072
  */
@@ -5058,6 +5079,10 @@ either way and cannot tell which it received.
5058
5079
  * IMAP UID - unique within mailbox, strictly ascending, never reused under same UIDVALIDITY
5059
5080
  */
5060
5081
  uid: number;
5082
+ /**
5083
+ * Relative position (1-based), changes on EXPUNGE
5084
+ */
5085
+ sequenceNumber: number;
5061
5086
  /**
5062
5087
  * Message size in octets in RFC 5322 format
5063
5088
  */
@@ -5066,10 +5091,117 @@ either way and cannot tell which it received.
5066
5091
  * Server receipt timestamp (INTERNALDATE)
5067
5092
  */
5068
5093
  internalDate: number;
5094
+ /**
5095
+ * Reference to parsed envelope data
5096
+ */
5097
+ envelopeId: UUID;
5098
+ /**
5099
+ * Reference to root body part for BODYSTRUCTURE
5100
+ */
5101
+ rootBodyPartId: UUID;
5102
+ /**
5103
+ * Storage URI for the message body (set when body has been fetched and stored)
5104
+ */
5105
+ bodyStorageKey?: string;
5106
+ /**
5107
+ * Message lifecycle status for move/delete operations. Defaults to `active` (normal, visible).
5108
+ */
5109
+ status: MessageStatus;
5110
+ /**
5111
+ * Sync status for move/delete operations, read as a pair with `status` (imap-mutations R3). The `synced` column default only applies to a row written without the field: the repository always supplies one, and an ordinary inbound sync writes `pending`, which nothing later promotes. So `pending` here does not mean an outstanding move or delete — `status` names that, `failed` marks an attempt about to be redelivered, and `abandoned` marks a mutation that gave up.
5112
+ */
5113
+ syncStatus: MessageSyncStatus;
5114
+ /**
5115
+ * Which mutation gave up on this message. Meaningful only while `syncStatus` is `abandoned`; `none` everywhere else, so the absent state is a named value rather than a missing attribute. Written by the same transition that writes `abandoned`, because a hand-back sets `status` back to `active` and that is the field which named the mutation.
5116
+ */
5117
+ abandonedMutation: MessageMutation;
5118
+ /**
5119
+ * Original mailbox ID before move (for restore from trash)
5120
+ */
5121
+ originalMailboxId?: UUID;
5122
+ /**
5123
+ * Original UID before move (for debugging/audit)
5124
+ */
5125
+ originalUid?: number;
5126
+ /**
5127
+ * Header-derived category. Defaults to `uncategorized`, a named value rather than absence. It covers two states — metadata-synced but not yet classified, and classified with nothing to say — and `classificationState` is what tells them apart.
5128
+ */
5129
+ category: MessageCategory;
5130
+ /**
5131
+ * Whether the header classifier has examined this message's body. Defaults to `NotExamined`, the named pending state every message written before this field existed carries. A field of its own rather than a reading of `category` or of `bodyStorageKey`: `uncategorized` is both the pending value and the classifier's own "nothing to say", and key presence is the storage fact, not the derivation's. Persistence-only — no response model exposes it — and it is what a later backfill selects the never-examined cohort by.
5132
+ */
5133
+ classificationState: MessageClassificationState;
5134
+ /**
5135
+ * Structured sender-authenticity signal derived from DKIM headers at classification time. Absent for messages classified before this field was introduced — absence means no signal.
5136
+ */
5137
+ authenticity?: MessageAuthenticity;
5138
+ /**
5139
+ * Sender-authenticity tier resolved at body-sync. Defaults to `NotEvaluated`, the named pending state every message written before the derivation existed carries. Top-level rather than a member of `authenticity` on purpose: that blob is absent for all unsigned mail, so a guard keyed on its absence cannot tell "never derived" from "nothing to derive" and would re-derive unsigned mail forever.
5140
+ */
5141
+ authenticityVerdict: AuthenticityVerdict;
5142
+ /**
5143
+ * Provider authentication-results signal parsed from Authentication-Results header. Absent for messages synced before this field was introduced.
5144
+ */
5145
+ authResult?: MessageAuthResult;
5146
+ /**
5147
+ * Provider spam-filter signal from X-Spam-* / X-SpamExperts-Class headers. Absent for messages synced before this field was introduced.
5148
+ */
5149
+ providerSpam?: MessageProviderSpam;
5150
+ /**
5151
+ * True when a List-Unsubscribe header is present, indicating a bulk/mailing-list sender. Defaults to false.
5152
+ */
5153
+ hasListUnsubscribe: boolean;
5154
+ /**
5155
+ * Set to true when Remit auto-moved this message out of Junk via the rescue heuristic. Guards against re-rescue loops. Defaults to false.
5156
+ */
5157
+ movedByRemit: boolean;
5158
+ /**
5159
+ * Remit's placement verdict, recorded when Remit decided to act (action != leave). Absent means left-in-place or synced before placement rolled out. Recorded in dry-run too, so the dark-ship distribution is queryable.
5160
+ */
5161
+ placementVerdict?: MessagePlacementVerdict;
5162
+ /**
5163
+ * Recorded when a standing filter moved this message at body-sync time (RFC 034). Absent means no filter moved it — a classifier move records `placementVerdict` instead, and a retroactive back-apply records neither. Drives the arbitrary-destination auto-moved badge and its undo.
5164
+ */
5165
+ filterMove?: MessageFilterMove;
5166
+ /**
5167
+ * Body-sync timestamp (epoch millis) the classifier's placement verdict was first decided, whether the verdict was to move the message or to leave it in place. Absent means placement has never been evaluated for this message. Guards `computePlacement` against a re-entrant body-sync pass (`fetchAndGetBody`'s `NoSuchKey` fallback, `syncBodies(..., force: true)`) re-deciding — and possibly reversing — a placement a user has since overridden by hand. `movedByRemit` remains the guard for a message that was placement-decided before this field existed.
5168
+ */
5169
+ placementDecidedAt?: number;
5170
+ /**
5171
+ * Recorded when the user reported this message as spam. Absent means never reported, or reported and then undone (`POST /messages/not-spam` clears it). Independent of the message's current folder — deliberately not derived from "sits in Junk", which is also true of a message Remit moved on its own.
5172
+ */
5173
+ spamReport?: MessageSpamReport;
5174
+ createdAt: number;
5175
+ updatedAt: number;
5069
5176
  /**
5070
5177
  * Message-ID header value for quick reference
5071
5178
  */
5072
5179
  messageIdHeader?: string;
5180
+ }
5181
+ /**
5182
+ * Core message metadata for API responses
5183
+ */
5184
+ export interface MessageSummaryResponse {
5185
+ /**
5186
+ * Primary identifier (internal UUID)
5187
+ */
5188
+ messageId: UUID;
5189
+ /**
5190
+ * Reference to parent mailbox
5191
+ */
5192
+ mailboxId: UUID;
5193
+ /**
5194
+ * IMAP UID - unique within mailbox, strictly ascending, never reused under same UIDVALIDITY
5195
+ */
5196
+ uid: number;
5197
+ /**
5198
+ * Message size in octets in RFC 5322 format
5199
+ */
5200
+ rfc822Size: number;
5201
+ /**
5202
+ * Server receipt timestamp (INTERNALDATE)
5203
+ */
5204
+ internalDate: number;
5073
5205
  /**
5074
5206
  * Message lifecycle status for move/delete operations. Defaults to `active` (normal, visible).
5075
5207
  */
@@ -5086,6 +5218,10 @@ either way and cannot tell which it received.
5086
5218
  * Structured sender-authenticity signal derived from DKIM headers at classification time. Absent for messages classified before this field was introduced — absence means no signal.
5087
5219
  */
5088
5220
  authenticity?: MessageAuthenticity;
5221
+ /**
5222
+ * Message-ID header value for quick reference
5223
+ */
5224
+ messageIdHeader?: string;
5089
5225
  /**
5090
5226
  * Present only when Remit auto-moved this message on body-sync. Absent means the message was not auto-moved by Remit.
5091
5227
  */
@@ -5194,7 +5330,7 @@ either way and cannot tell which it received.
5194
5330
  */
5195
5331
  parentBodyPartId?: UUID;
5196
5332
  /**
5197
- * IMAP section path (e.g., '1', '1.2', '2.1.3')
5333
+ * Storage path of the part within its message: '0' is the root, otherwise the IMAP section number (e.g., '1', '1.2', '2.1.3'). '<path>.0' is the root of the forwarded message a message/rfc822 part at <path> carries, which is not an IMAP section.
5198
5334
  */
5199
5335
  partPath: string;
5200
5336
  /**
@@ -5264,6 +5400,10 @@ either way and cannot tell which it received.
5264
5400
  * Primary identifier
5265
5401
  */
5266
5402
  bodyPartId: UUID;
5403
+ /**
5404
+ * Storage path of the part within its message: '0' is the root, otherwise the IMAP section number (e.g., '1', '1.2', '2.1.3'). '<path>.0' is the root of the forwarded message a message/rfc822 part at <path> carries, which is not an IMAP section.
5405
+ */
5406
+ partPath: string;
5267
5407
  /**
5268
5408
  * MIME type (TEXT, IMAGE, APPLICATION, etc.)
5269
5409
  */
@@ -6218,6 +6358,21 @@ domain already uses"; it does not close it.
6218
6358
  createdAt: number;
6219
6359
  updatedAt: number;
6220
6360
  }
6361
+ /**
6362
+ * A message whose body part rows a repair dropped because they were stored
6363
+ wrong, queued for message sync to read its BODYSTRUCTURE again from the mail
6364
+ server. Message sync drains the queue once per message: the row goes when
6365
+ the message is saved again or the server no longer holds it, whatever parts
6366
+ came back.
6367
+ */
6368
+ export interface BodyStructureRefetch {
6369
+ /**
6370
+ * The message whose structure is to be read again.
6371
+ */
6372
+ messageId: UUID;
6373
+ createdAt: number;
6374
+ updatedAt: number;
6375
+ }
6221
6376
  /**
6222
6377
  * Reference to the complete raw message stored externally
6223
6378
  */
@@ -6320,33 +6475,6 @@ domain already uses"; it does not close it.
6320
6475
  createdAt: number;
6321
6476
  updatedAt: number;
6322
6477
  }
6323
- /**
6324
- * Inline storage for small body parts (typically < 64KB). Avoids external storage overhead.
6325
- */
6326
- export interface BodyPartContent {
6327
- /**
6328
- * Primary identifier
6329
- */
6330
- bodyPartContentId: UUID;
6331
- /**
6332
- * Reference to parent message
6333
- */
6334
- messageId: UUID;
6335
- /**
6336
- * Reference to parent body part
6337
- */
6338
- bodyPartId: UUID;
6339
- /**
6340
- * The actual content (for small inline content only)
6341
- */
6342
- content: string;
6343
- /**
6344
- * Content length in bytes
6345
- */
6346
- contentLength: number;
6347
- createdAt: number;
6348
- updatedAt: number;
6349
- }
6350
6478
  /**
6351
6479
  * One occurrence of a CalendarObject, flattened so a date range can be queried
6352
6480
  instead of expanded (issue #15). Every row is derived from
@@ -6484,49 +6612,6 @@ single `get` checks whether it is already set.
6484
6612
  createdAt: number;
6485
6613
  updatedAt: number;
6486
6614
  }
6487
- /**
6488
- * Persisted semantic-anchor payload for a Filter with `hasAnchor: true` (RFC
6489
- 034 Decision 2). One row only for a filter with a semantic anchor — a
6490
- purely-literal filter has none.
6491
-
6492
- Keys mirror `Filter`'s primary key, so once the index-time worker has a
6493
- candidate `filterId` from `byAccountAndState`, fetching its anchor is a
6494
- single deterministic `get`, never a query.
6495
-
6496
- Deliberately sets no `gsi1pk`/`gsi1sk`: never a member of
6497
- `byAccountAndState`, so it is never replicated into that GSI and never
6498
- loaded by the index-time worker's per-message filter listing — only by the
6499
- explicit `get` once a filter is already a semantic candidate (RFC 034
6500
- Decision 2.3).
6501
- */
6502
- export interface FilterAnchor {
6503
- /**
6504
- * Owning account configuration — mirrors the sibling Filter row's key
6505
- */
6506
- accountConfigId: UUID;
6507
- /**
6508
- * Filter this anchor belongs to — mirrors the sibling Filter row's key
6509
- */
6510
- filterId: UUID;
6511
- /**
6512
- * Persisted anchor vector: mean-pooled (or dominant-chunk) from the anchor message's chunk vectors at save time (RFC 034 Decision 2.1). ~18 KB as DynamoDB decimal-string-encoded numbers (Decision 2.3) — well under the 400 KB item limit, written once, never grown.
6513
- */
6514
- anchorEmbedding: number[];
6515
- /**
6516
- * `<modelId>@<dimensions>` identifier, e.g. "amazon.titan-embed-text-v2:0@1024" — the same id packages/search-service/src/embeddings.ts derives for chunk vectors. Lets a migration detect anchors whose model has gone stale (RFC 034 Decision 2.4).
6517
- */
6518
- anchorEmbeddingId: string;
6519
- /**
6520
- * The anchor message's textPreview at save time, bounded to buildTextPreview's existing budget (RFC 034 Decision 2.1). Retained so a stale anchor is always re-embeddable without depending on the source message still existing (Decision 2.4).
6521
- */
6522
- anchorSourceText: String512;
6523
- /**
6524
- * Provenance/display only — "based on this message" (RFC 034 Decision 2.1). Never re-read at match time. May dangle if the source message is later deleted; anchorEmbedding/anchorSourceText are unaffected, since they are copies, not references.
6525
- */
6526
- anchorMessageId: UUID;
6527
- createdAt: number;
6528
- updatedAt: number;
6529
- }
6530
6615
  export interface MicrosoftOAuthStartRequest {
6531
6616
  /**
6532
6617
  * Optional email hint for the Microsoft login page
@@ -7217,23 +7302,6 @@ declare namespace Paths {
7217
7302
  export type $401 = void;
7218
7303
  }
7219
7304
  }
7220
- namespace SemanticSearch {
7221
- export interface QueryParameters {
7222
- query: string;
7223
- mailboxId?: Components.Schemas.UUID;
7224
- sentDateFrom?: number;
7225
- sentDateTo?: number;
7226
- hasAttachment?: boolean;
7227
- hasStars?: boolean;
7228
- isRead?: boolean;
7229
- category?: Components.Schemas.MessageCategory;
7230
- limit?: number;
7231
- }
7232
- namespace Responses {
7233
- export type $200 = void;
7234
- export type $401 = void;
7235
- }
7236
- }
7237
7305
  namespace CreateOutboxMessage {
7238
7306
  export type RequestBody = Components.Schemas.CreateOutboxMessageInput;
7239
7307
  namespace Responses {
@@ -7725,7 +7793,7 @@ export interface OperationMethods {
7725
7793
  config?: AxiosRequestConfig
7726
7794
  ): OperationResponse<Paths.DeleteLabel.Responses.$204>;
7727
7795
  /**
7728
- * createOrganizeJob - Start a one-time "all like these" back-apply: match the corpus against the given predicate and apply the action to every match, in one pass. Returns immediately with an organizeJobId; poll GET /accounts/{accountId}/organize/{organizeJobId} for state and counts. Never creates a Filter or FilterAnchor row (RFC 034 recap).
7796
+ * createOrganizeJob - Start a one-time "all like these" back-apply: match the corpus against the given predicate and apply the action to every match, in one pass. Returns immediately with an organizeJobId; poll GET /accounts/{accountId}/organize/{organizeJobId} for state and counts. Never creates a Filter row (RFC 034 recap).
7729
7797
  */
7730
7798
  'createOrganizeJob'(
7731
7799
  parameters?: Parameters<Paths.CreateOrganizeJob.PathParameters> | null,
@@ -8057,14 +8125,6 @@ Counting: `count=true` answers how many CONVERSATIONS match, over the whole scop
8057
8125
  data?: any,
8058
8126
  config?: AxiosRequestConfig
8059
8127
  ): OperationResponse<Paths.SearchThreads.Responses.$200>;
8060
- /**
8061
- * semanticSearch - Run a semantic vector search across the caller's indexed messages.
8062
- */
8063
- 'semanticSearch'(
8064
- parameters?: Parameters<Paths.SemanticSearch.QueryParameters> | null,
8065
- data?: any,
8066
- config?: AxiosRequestConfig
8067
- ): OperationResponse<Paths.SemanticSearch.Responses.$200>;
8068
8128
  /**
8069
8129
  * createOutboxMessage - Create a new outbox message (draft or send immediately). A send-immediately create from an account whose syncedServices leave out Mail is refused with 400 `mail_sync_off`.
8070
8130
  */
@@ -8552,7 +8612,7 @@ export interface PathsDictionary {
8552
8612
  };
8553
8613
  ['/accounts/{accountId}/organize']: {
8554
8614
  /**
8555
- * createOrganizeJob - Start a one-time "all like these" back-apply: match the corpus against the given predicate and apply the action to every match, in one pass. Returns immediately with an organizeJobId; poll GET /accounts/{accountId}/organize/{organizeJobId} for state and counts. Never creates a Filter or FilterAnchor row (RFC 034 recap).
8615
+ * createOrganizeJob - Start a one-time "all like these" back-apply: match the corpus against the given predicate and apply the action to every match, in one pass. Returns immediately with an organizeJobId; poll GET /accounts/{accountId}/organize/{organizeJobId} for state and counts. Never creates a Filter row (RFC 034 recap).
8556
8616
  */
8557
8617
  'post'(
8558
8618
  parameters?: Parameters<Paths.CreateOrganizeJob.PathParameters> | null,
@@ -8927,16 +8987,6 @@ Counting: `count=true` answers how many CONVERSATIONS match, over the whole scop
8927
8987
  config?: AxiosRequestConfig
8928
8988
  ): OperationResponse<Paths.SearchThreads.Responses.$200>;
8929
8989
  };
8930
- ['/search/semantic']: {
8931
- /**
8932
- * semanticSearch - Run a semantic vector search across the caller's indexed messages.
8933
- */
8934
- 'get'(
8935
- parameters?: Parameters<Paths.SemanticSearch.QueryParameters> | null,
8936
- data?: any,
8937
- config?: AxiosRequestConfig
8938
- ): OperationResponse<Paths.SemanticSearch.Responses.$200>;
8939
- };
8940
8990
  ['/outbox']: {
8941
8991
  /**
8942
8992
  * createOutboxMessage - Create a new outbox message (draft or send immediately). A send-immediately create from an account whose syncedServices leave out Mail is refused with 400 `mail_sync_off`.
@@ -9261,6 +9311,8 @@ export type QuarantineListResponse = Components.Schemas.QuarantineListResponse;
9261
9311
  export type Quarantine = Components.Schemas.Quarantine;
9262
9312
  export type QuarantineMimeNode = Components.Schemas.QuarantineMimeNode;
9263
9313
  export type QuarantineResponse = Components.Schemas.QuarantineResponse;
9314
+ export type SyncWarning = Components.Schemas.SyncWarning;
9315
+ export type SyncWarningResponse = Components.Schemas.SyncWarningResponse;
9264
9316
  export type ConfigDescriptionResponse = Components.Schemas.ConfigDescriptionResponse;
9265
9317
  export type AccountConfig = Components.Schemas.AccountConfig;
9266
9318
  export type AccountConfigResponse = Components.Schemas.AccountConfigResponse;
@@ -9281,6 +9333,7 @@ export type SystemUpdateRun = Components.Schemas.SystemUpdateRun;
9281
9333
  export type ApplyUpdateInput = Components.Schemas.ApplyUpdateInput;
9282
9334
  export type Mailbox = Components.Schemas.Mailbox;
9283
9335
  export type MailboxResponse = Components.Schemas.MailboxResponse;
9336
+ export type MailboxListResponse = Components.Schemas.MailboxListResponse;
9284
9337
  export type CreateMailboxInput = Components.Schemas.CreateMailboxInput;
9285
9338
  export type RenameMailboxInput = Components.Schemas.RenameMailboxInput;
9286
9339
  export type AppointFolderRoleInput = Components.Schemas.AppointFolderRoleInput;
@@ -9333,13 +9386,14 @@ export type MessageAuthenticity = Components.Schemas.MessageAuthenticity;
9333
9386
  export type AutoMovedInfo = Components.Schemas.AutoMovedInfo;
9334
9387
  export type LabelSummaryResponse = Components.Schemas.LabelSummaryResponse;
9335
9388
  export type MessageSpamReport = Components.Schemas.MessageSpamReport;
9389
+ export type ThreadMessageListResponse = Components.Schemas.ThreadMessageListResponse;
9336
9390
  export type ThreadSearchResponse = Components.Schemas.ThreadSearchResponse;
9337
- export type SemanticSearchResult = Components.Schemas.SemanticSearchResult;
9338
9391
  export type CreateOutboxMessageInput = Components.Schemas.CreateOutboxMessageInput;
9339
9392
  export type OutboxMessage = Components.Schemas.OutboxMessage;
9340
9393
  export type OutboxMessageResponse = Components.Schemas.OutboxMessageResponse;
9341
9394
  export type OutboxAttachment = Components.Schemas.OutboxAttachment;
9342
9395
  export type OutboxAttachmentResponse = Components.Schemas.OutboxAttachmentResponse;
9396
+ export type OutboxMessageListResponse = Components.Schemas.OutboxMessageListResponse;
9343
9397
  export type UpdateOutboxMessageInput = Components.Schemas.UpdateOutboxMessageInput;
9344
9398
  export type MintOutboxAttachmentInput = Components.Schemas.MintOutboxAttachmentInput;
9345
9399
  export type MintOutboxAttachmentResponse = Components.Schemas.MintOutboxAttachmentResponse;
@@ -9360,11 +9414,12 @@ export type AddressResponse = Components.Schemas.AddressResponse;
9360
9414
  export type UpdateAddressInput = Components.Schemas.UpdateAddressInput;
9361
9415
  export type UpdateAddressFlagsInput = Components.Schemas.UpdateAddressFlagsInput;
9362
9416
  export type DescribeMessageResponse = Components.Schemas.DescribeMessageResponse;
9363
- export type Message = Components.Schemas.Message;
9417
+ export type MessageRecord = Components.Schemas.MessageRecord;
9364
9418
  export type MessageAuthResult = Components.Schemas.MessageAuthResult;
9365
9419
  export type MessageProviderSpam = Components.Schemas.MessageProviderSpam;
9366
9420
  export type MessagePlacementVerdict = Components.Schemas.MessagePlacementVerdict;
9367
9421
  export type MessageFilterMove = Components.Schemas.MessageFilterMove;
9422
+ export type Message = Components.Schemas.Message;
9368
9423
  export type MessageSummaryResponse = Components.Schemas.MessageSummaryResponse;
9369
9424
  export type EnvelopeResponse = Components.Schemas.EnvelopeResponse;
9370
9425
  export type EnvelopeAddressResponse = Components.Schemas.EnvelopeAddressResponse;
@@ -9408,13 +9463,12 @@ export type MessageFlagPush = Components.Schemas.MessageFlagPush;
9408
9463
  export type Envelope = Components.Schemas.Envelope;
9409
9464
  export type SenderSignerStanding = Components.Schemas.SenderSignerStanding;
9410
9465
  export type BodyPartParameter = Components.Schemas.BodyPartParameter;
9466
+ export type BodyStructureRefetch = Components.Schemas.BodyStructureRefetch;
9411
9467
  export type RawMessageStorage = Components.Schemas.RawMessageStorage;
9412
9468
  export type BodyPartStorage = Components.Schemas.BodyPartStorage;
9413
- export type BodyPartContent = Components.Schemas.BodyPartContent;
9414
9469
  export type CalendarEventIndex = Components.Schemas.CalendarEventIndex;
9415
9470
  export type CalendarFeedToken = Components.Schemas.CalendarFeedToken;
9416
9471
  export type MessageLabel = Components.Schemas.MessageLabel;
9417
- export type FilterAnchor = Components.Schemas.FilterAnchor;
9418
9472
  export type MicrosoftOAuthStartRequest = Components.Schemas.MicrosoftOAuthStartRequest;
9419
9473
  export type MicrosoftOAuthStartResponse = Components.Schemas.MicrosoftOAuthStartResponse;
9420
9474
  export type IndexType = Components.Schemas.IndexType;
@@ -9422,6 +9476,7 @@ export type AccountExportState = Components.Schemas.AccountExportState;
9422
9476
  export type CanonicalMailboxRole = Components.Schemas.CanonicalMailboxRole;
9423
9477
  export type QuarantineFailureStage = Components.Schemas.QuarantineFailureStage;
9424
9478
  export type QuarantineFailureCode = Components.Schemas.QuarantineFailureCode;
9479
+ export type SyncWarningStage = Components.Schemas.SyncWarningStage;
9425
9480
  export type AccountConfigState = Components.Schemas.AccountConfigState;
9426
9481
  export type AccountAuthType = Components.Schemas.AccountAuthType;
9427
9482
  export type AccountService = Components.Schemas.AccountService;
@@ -9460,7 +9515,6 @@ export type MessageStatus = Components.Schemas.MessageStatus;
9460
9515
  export type MessageSyncStatus = Components.Schemas.MessageSyncStatus;
9461
9516
  export type MessageMutation = Components.Schemas.MessageMutation;
9462
9517
  export type PlacementAction = Components.Schemas.PlacementAction;
9463
- export type SemanticSearchChunkType = Components.Schemas.SemanticSearchChunkType;
9464
9518
  export type OutboxMessageStatus = Components.Schemas.OutboxMessageStatus;
9465
9519
  export type OutboxAttachmentState = Components.Schemas.OutboxAttachmentState;
9466
9520
  export type OutboxAttachmentRejectionReason = Components.Schemas.OutboxAttachmentRejectionReason;
@@ -9490,6 +9544,7 @@ export type SenderOverride = Components.Schemas.SenderOverride;
9490
9544
  export type AccountSettingName = Components.Schemas.AccountSettingName;
9491
9545
  export type ConfigImportState = Components.Schemas.ConfigImportState;
9492
9546
  export type ConfigImportRefKind = Components.Schemas.ConfigImportRefKind;
9547
+ export type SyncWarningState = Components.Schemas.SyncWarningState;
9493
9548
  export type MessagePlacementMoveState = Components.Schemas.MessagePlacementMoveState;
9494
9549
  export type FlagPushOperation = Components.Schemas.FlagPushOperation;
9495
9550
  export type MessageFlagPushState = Components.Schemas.MessageFlagPushState;