@pithy-sh/support 0.7.0 → 0.8.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/README.md CHANGED
@@ -12,7 +12,7 @@ pithy add support
12
12
 
13
13
  **A shared inbox.** Assign a conversation to somebody, filter the inbox by who has it, and see who else has a thread open before you reply: `POST /support/threads/:id/assign` behind `support:threads:assign`, `assignee=<ref>` or `assignee=none` on the listing, every handover kept in the thread's history, and one `support.thread` presence room per thread, with `viewing` and `replying`. Your own signed-in staff reach both through `support({ staff: { readPower, assignPower } })`, on unassignable roles other than the one ownership transfer confers, so only an operator can confer them. The seam is [`docs/CONTROL-PLANE.md`](../../docs/CONTROL-PLANE.md).
14
14
 
15
- **Search, by words and by meaning.** `GET /support/threads/search` takes `q`, a `mode` (`keyword`, `semantic` or `hybrid`), a `limit` (20, at most 50) and the inbox list's filters, and returns ranked threads, each named by its best-matching message with that message's raw `bm25` and similarity. Keyword is FTS5 with `search.fts` on and the `LIKE` scan otherwise; hybrid fuses it with semantic search by rank, so a paraphrase is found and an order number still comes first. The inbox list no longer takes `q`. **Semantic search costs a second inference per inbound message on your own Workers AI binding**, on top of classification — roughly double the per-message AI cost — so `search: { semantic: true }` is off until you turn it on. `pithy support provision` creates the Vectorize index and backfills it once, and `pithy vector reprocess --index support-messages` re-embeds after a model change, with no `vector()` composed. Vectors carry message ids only. See [`docs/commands/support.md`](../../docs/commands/support.md#search).
15
+ **Search, by words and by meaning.** `POST /support/threads/search` takes, in its body, `q`, a `mode` (`keyword`, `semantic` or `hybrid`), a `limit` (20, at most 50) and the inbox list's filters, and returns ranked threads, each named by its best-matching message with that message's raw `bm25` and similarity. Keyword is FTS5 with `search.fts` on and the `LIKE` scan otherwise; hybrid fuses it with semantic search by rank, so a paraphrase is found and an order number still comes first. The inbox list no longer takes `q`. **Semantic search costs a second inference per inbound message on your own Workers AI binding**, on top of classification — roughly double the per-message AI cost — so `search: { semantic: true }` is off until you turn it on. `pithy support provision` creates the Vectorize index and backfills it once, and `pithy vector reprocess --index support-messages` re-embeds after a model change, with no `vector()` composed. Vectors carry message ids only. See [`docs/commands/support.md`](../../docs/commands/support.md#search).
16
16
 
17
17
  **Replies come from the inbox.** A mailed reply is sent from the address the customer wrote to, under the name of whoever answered: `"Jim Scott" <support@help.example.com>`, with that inbox as the `Reply-To`. `reply.fromName` is the display name, with `{agent}` replaced by the agent's name (default `{agent}`); with no agent name, the email capability's `fromName` is used. A fixed `reply.fromName` with no `{agent}` is used for every reply. Support declares the addresses it sends as, `inboundAddresses` and `reply.replyToAddress`, through `email().enqueueAs` (`@pithy-sh/email` ^0.9.0; an older one is refused at compose). A thread whose inbox is no longer claimed is answered from `reply.replyToAddress`, or refused when none is set. A domain Email Service cannot send from fails the job with the domain named, and nothing is sent from another address in its place. `pithy doctor` names each sending domain, inbound or reply-to, that cannot send.
18
18
 
@@ -15,7 +15,7 @@ import { type SenderPeers } from "../link/sender";
15
15
  import { sendReply } from "../reply/send";
16
16
  import type { SupportReplySnippets } from "../reply/snippets";
17
17
  import type { SupportAssignResponse, SupportFlagsResponse, SupportMyThreadResponse, SupportMyThreadsResponse, SupportReclassifiedResponse, SupportReplySentResponse, SupportReplyView, SupportSearchResponse, SupportSubmissionResponse, SupportThreadResponse, SupportThreadsResponse, SupportThreadView } from "./responses";
18
- import type { ArchiveThreadInput, AssignThreadInput, FlagsInput, ListThreadsQuery, MyThreadsQuery, RepliesQuery, ReplyInput, SearchThreadsQuery, SubmitFeedbackInput } from "./schemas";
18
+ import type { ArchiveThreadInput, AssignThreadInput, FlagsInput, ListThreadsQuery, MyThreadsQuery, RepliesQuery, ReplyInput, SearchThreadsBody, SubmitFeedbackInput } from "./schemas";
19
19
  /**
20
20
  * The support handlers — every one of them behind the `control-plane` gate, and every one of them
21
21
  * taking already-validated values.
@@ -71,7 +71,7 @@ export declare function listInbox(deps: HandlerDeps, query: ListThreadsQuery, vi
71
71
  * Search the inbox: keyword and semantic, ranked as one. The semantic seams are whatever this Worker
72
72
  * was given — absent bindings skip that backend and say so, rather than failing the search.
73
73
  */
74
- export declare function searchInbox(deps: HandlerDeps, query: SearchThreadsQuery, viewer: string): Promise<SupportSearchResponse>;
74
+ export declare function searchInbox(deps: HandlerDeps, query: SearchThreadsBody, viewer: string): Promise<SupportSearchResponse>;
75
75
  /** Read one conversation in full. */
76
76
  export declare function readConversation(deps: HandlerDeps, threadId: string): Promise<SupportThreadResponse>;
77
77
  /** Mark a conversation done, or reopen it. */
@@ -1 +1 @@
1
- {"version":3,"file":"handlers.d.ts","sourceRoot":"","sources":["../../src/http/handlers.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"handlers.d.ts","sourceRoot":"","sources":["../../src/http/handlers.ts"],"names":[],"mappings":"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"}
@@ -55,7 +55,7 @@ async function searchInbox(deps, query, viewer) {
55
55
  q: query.q,
56
56
  ...query.mode !== void 0 ? { mode: query.mode } : {},
57
57
  ...query.limit !== void 0 ? { limit: query.limit } : {},
58
- archived: query.archived === "true",
58
+ archived: query.archived === true,
59
59
  category: query.category,
60
60
  declaredCategory: query.declaredCategory,
61
61
  priority: query.priority,
@@ -327,7 +327,7 @@ export declare const SupportSearchResultView: z.ZodObject<{
327
327
  similarity: z.ZodOptional<z.ZodNumber>;
328
328
  }, z.core.$strip>;
329
329
  export type SupportSearchResultView = z.output<typeof SupportSearchResultView>;
330
- /** `GET {base}/threads/search`. */
330
+ /** `POST {base}/threads/search`. */
331
331
  export declare const SupportSearchResponse: z.ZodObject<{
332
332
  mode: z.ZodEnum<{
333
333
  hybrid: "hybrid";
@@ -702,9 +702,8 @@ export type SupportFlagsResponse = z.output<typeof SupportFlagsResponse>;
702
702
  * Below is the same projection for the other consumer: a management client reading a Worker **it does
703
703
  * not control**. That client is crossing a trust boundary — a fork, a bug, a half-finished deploy, or a
704
704
  * hostile Worker each put a member here that no enum of ours declares — and under the strict schema one
705
- * such token costs it the entire response. It cost `pithy-sh/dashboard#15` exactly that: one
706
- * unrecognized `channel` and the support pane rendered zero of twenty-five conversations. The client
707
- * then had to widen our shape locally, which is the hand-held mirror `#113` exists to forbid.
705
+ * such token costs it the entire response: one unrecognized `channel` and a support pane renders none of
706
+ * its conversations, and the client is left widening our shape locally, the hand-held mirror the kit forbids.
708
707
  *
709
708
  * So the tolerance is published rather than reimplemented, by the one pattern
710
709
  * `@pithy-sh/core/src/projection/asRead` states for the whole kit: same objects, every enum read as a
@@ -845,7 +844,7 @@ export declare const SupportThreadsResponseAsRead: z.ZodObject<{
845
844
  nextCursor: z.ZodNullable<z.ZodString>;
846
845
  }, z.core.$strip>;
847
846
  export type SupportThreadsResponseAsRead = z.output<typeof SupportThreadsResponseAsRead>;
848
- /** `GET {base}/threads/search`, as a client that does not control the Worker must read it. */
847
+ /** `POST {base}/threads/search`, as a client that does not control the Worker must read it. */
849
848
  export declare const SupportSearchResponseAsRead: z.ZodObject<{
850
849
  mode: z.ZodString;
851
850
  backends: z.ZodObject<{
@@ -1 +1 @@
1
- {"version":3,"file":"responses.d.ts","sourceRoot":"","sources":["../../src/http/responses.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"responses.d.ts","sourceRoot":"","sources":["../../src/http/responses.ts"],"names":[],"mappings":"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"}
@@ -27,16 +27,14 @@ import { asRead } from "@pithy-sh/core/src/projection/asRead";
27
27
  *
28
28
  * **A browser imports this file, so it reaches no module that needs the Workers runtime.** That is not
29
29
  * a preference about bundle size; it is what "a client validates what comes back" means once the client
30
- * is a Vite program with the DOM lib and no Workers types. This file imported `SUPPORT_BILLING_SCOPE`
31
- * from `link/sender.ts` for one release and brought D1, Kysely and two capabilities' table maps with it,
32
- * which took `pithy-sh/dashboard`'s client build down on an error in `@pithy-sh/auth` (#419). The rule is
33
- * held by `tooling/browser-scopes`, which compiles this module with `types: []` and asks the compiler
30
+ * is a Vite program with the DOM lib and no Workers types: an import of `link/sender.ts` would bring D1,
31
+ * Kysely and two capabilities' table maps into that build. The rule is held by `tooling/browser-scopes`, which compiles this module with `types: []` and asks the compiler
34
32
  * which files that program included.
35
33
  *
36
34
  * **A field added here later is `.optional()`, not merely `.nullable()`.** This module is read across a
37
35
  * version boundary — a management client validates a response with this schema against a customer's
38
36
  * Worker at whatever kit version it is on — so an additive required key fails `safeParse` for everyone
39
- * below that release and takes the whole pane with it (#450). Absent then means *this Worker cannot
37
+ * below that release and takes the whole pane with it. Absent then means *this Worker cannot
40
38
  * say*, which is a different fact from `null`.
41
39
  */
42
40
  /** Where a page resumes, or the end of the list. */
@@ -186,7 +184,7 @@ const SupportSearchResultView = z.object({
186
184
  bm25: z.number().optional().describe("That message's FTS5 `bm25`, raw: lower is better, and comparable only within one search. Absent when FTS5 did not run or did not match it — including on the `LIKE` scan, which has no score."),
187
185
  similarity: z.number().optional().describe("That message's similarity to the query in the semantic index, raw: higher is closer. Absent when semantic search did not run or did not match it. Never normalized against `bm25` — the two are reported as they are.")
188
186
  }).describe("One thread a search found, named by its best-matching message, with that message's raw scores.");
189
- /** `GET {base}/threads/search`. */
187
+ /** `POST {base}/threads/search`. */
190
188
  const SupportSearchResponse = z.object({
191
189
  mode: z.enum([
192
190
  "keyword",
@@ -278,9 +276,8 @@ const SupportFlagsResponse = z.object({ ok: z.literal(true).describe("Always tru
278
276
  * Below is the same projection for the other consumer: a management client reading a Worker **it does
279
277
  * not control**. That client is crossing a trust boundary — a fork, a bug, a half-finished deploy, or a
280
278
  * hostile Worker each put a member here that no enum of ours declares — and under the strict schema one
281
- * such token costs it the entire response. It cost `pithy-sh/dashboard#15` exactly that: one
282
- * unrecognized `channel` and the support pane rendered zero of twenty-five conversations. The client
283
- * then had to widen our shape locally, which is the hand-held mirror `#113` exists to forbid.
279
+ * such token costs it the entire response: one unrecognized `channel` and a support pane renders none of
280
+ * its conversations, and the client is left widening our shape locally, the hand-held mirror the kit forbids.
284
281
  *
285
282
  * So the tolerance is published rather than reimplemented, by the one pattern
286
283
  * `@pithy-sh/core/src/projection/asRead` states for the whole kit: same objects, every enum read as a
@@ -304,7 +301,7 @@ const SupportListedThreadViewAsRead = asRead(SupportListedThreadView);
304
301
  const SupportMessageViewAsRead = asRead(SupportMessageView);
305
302
  /** `GET {base}/threads`, as a client that does not control the Worker must read it. */
306
303
  const SupportThreadsResponseAsRead = asRead(SupportThreadsResponse);
307
- /** `GET {base}/threads/search`, as a client that does not control the Worker must read it. */
304
+ /** `POST {base}/threads/search`, as a client that does not control the Worker must read it. */
308
305
  const SupportSearchResponseAsRead = asRead(SupportSearchResponse);
309
306
  /** `GET {base}/threads/:id`, as a client that does not control the Worker must read it. */
310
307
  const SupportThreadResponseAsRead = asRead(SupportThreadResponse);
@@ -8,7 +8,7 @@ import { type HandlerDeps } from "./handlers";
8
8
  * The support routes, their verification strategies, and what each accepts:
9
9
  *
10
10
  * GET /support/threads → the inbox (control-plane: support:threads:read) query: ListThreadsQuery
11
- * GET /support/threads/search → search (control-plane: support:threads:read) query: SearchThreadsQuery
11
+ * POST /support/threads/search → search (control-plane: support:threads:read) json: SearchThreadsBody
12
12
  * GET /support/threads/:id → one thread (control-plane: support:threads:read) param: ThreadIdParam
13
13
  * POST /support/threads/:id/archive → done/reopen (control-plane: support:threads:archive) param + json
14
14
  * POST /support/threads/:id/assign → who has it (control-plane: support:threads:assign) param + json
@@ -58,8 +58,8 @@ import { type HandlerDeps } from "./handlers";
58
58
  * person who most needs to reach support is often the one whose access is broken, and a role the kit
59
59
  * invented would make one adopter's account model a condition on everybody's ability to report a bug.
60
60
  *
61
- * But an adopter whose *own* model makes some submissions act-on-behalf-of — `pithy-sh/dashboard#10`'s
62
- * discount application is made for an organization, and a member may not make one — needs somewhere to
61
+ * But an adopter whose *own* model makes some submissions act-on-behalf-of — a discount application made
62
+ * for an organization, which a member may not make — needs somewhere to
63
63
  * put that check, and it must not be the client. **The seam for it already exists, in the composition
64
64
  * contract rather than in this capability's config**, and it is documented here because it was not
65
65
  * discoverable rather than because it was missing:
@@ -1 +1 @@
1
- {"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../../src/http/routes.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0CAA0C,CAAC;AAM7E,OAAO,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC1C,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAE3D,OAAO,EAGL,KAAK,WAAW,EAWjB,MAAM,YAAY,CAAC;AAoCpB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkGG;AAEH,2CAA2C;AAC3C,MAAM,WAAW,oBAAoB;IACnC,+DAA+D;IAC/D,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;;;;OAMG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,qDAAqD;IACrD,WAAW,EAAE,CAAC,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,KAAK,OAAO,CAAC,WAAW,CAAC,CAAC;IAChE;;;OAGG;IACH,KAAK,CAAC,EAAE,kBAAkB,CAAC;CAC5B;AAuCD,mFAAmF;AACnF,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,oBAAoB,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,YAAY,CAAC,KAAK,IAAI,CAqNtG"}
1
+ {"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../../src/http/routes.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0CAA0C,CAAC;AAM7E,OAAO,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC1C,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAE3D,OAAO,EAGL,KAAK,WAAW,EAWjB,MAAM,YAAY,CAAC;AAoCpB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkGG;AAEH,2CAA2C;AAC3C,MAAM,WAAW,oBAAoB;IACnC,+DAA+D;IAC/D,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;;;;OAMG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,qDAAqD;IACrD,WAAW,EAAE,CAAC,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,KAAK,OAAO,CAAC,WAAW,CAAC,CAAC;IAChE;;;OAGG;IACH,KAAK,CAAC,EAAE,kBAAkB,CAAC;CAC5B;AAuCD,mFAAmF;AACnF,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,oBAAoB,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,YAAY,CAAC,KAAK,IAAI,CAsNtG"}
@@ -3,7 +3,7 @@
3
3
  import { requireAuth, requireStaff } from "./guards.js";
4
4
  import { archiveConversation, assignConversation, listInbox, listMyThreads, listReplies, readConversation, readMyThread, reclassifyConversation, replyToConversation, searchInbox, submitFeedbackRequest, updateFlags } from "./handlers.js";
5
5
  import { SupportArchiveResponse, SupportAssignResponse, SupportFlagsResponse, SupportMyThreadResponse, SupportMyThreadsResponse, SupportReclassifiedResponse, SupportRepliesResponse, SupportReplySentResponse, SupportSearchResponse, SupportSubmissionResponse, SupportThreadResponse, SupportThreadsResponse } from "./responses.js";
6
- import { ArchiveThreadInput, AssignThreadInput, FlagsInput, ListThreadsQuery, MyThreadsQuery, RepliesQuery, ReplyInput, SearchThreadsQuery, SubmitFeedbackInput, ThreadIdParam } from "./schemas.js";
6
+ import { ArchiveThreadInput, AssignThreadInput, FlagsInput, ListThreadsQuery, MyThreadsQuery, RepliesQuery, ReplyInput, SearchThreadsBody, SubmitFeedbackInput, ThreadIdParam } from "./schemas.js";
7
7
  import { SUPPORT_THREADS_ARCHIVE_SCOPE, SUPPORT_THREADS_ASSIGN_SCOPE, SUPPORT_THREADS_FLAG_SCOPE, SUPPORT_THREADS_READ_SCOPE, SUPPORT_THREADS_RECLASSIFY_SCOPE, SUPPORT_THREADS_REPLY_SCOPE } from "./scopes.js";
8
8
  import { InternalError } from "@pithy-sh/core/src/error/pithyError";
9
9
  import { requireControlPlane } from "@pithy-sh/core/src/controlPlane/http/guard";
@@ -54,12 +54,13 @@ function registerSupportRoutes(options) {
54
54
  scopes: [SUPPORT_THREADS_READ_SCOPE],
55
55
  responses: { 200: SupportThreadsResponse }
56
56
  }), requireControlPlane(SUPPORT_THREADS_READ_SCOPE), validate("query", ListThreadsQuery), async (c) => c.json(await listInbox(await resolve(c), c.req.valid("query"), viewer(c))));
57
- app.get(`${base}/threads/search`, describeRoute({
57
+ app.post(`${base}/threads/search`, describeRoute({
58
58
  summary: "Search the inbox, by words and by meaning, ranked as one.",
59
+ description: "The words travel in the body, because they are often a customer's address or order number and a query string is written to every request log between the client and the Worker. Read-only.",
59
60
  verification: "control-plane",
60
61
  scopes: [SUPPORT_THREADS_READ_SCOPE],
61
62
  responses: { 200: SupportSearchResponse }
62
- }), requireControlPlane(SUPPORT_THREADS_READ_SCOPE), validate("query", SearchThreadsQuery), async (c) => c.json(await searchInbox(await resolve(c), c.req.valid("query"), viewer(c))));
63
+ }), requireControlPlane(SUPPORT_THREADS_READ_SCOPE), validate("json", SearchThreadsBody), async (c) => c.json(await searchInbox(await resolve(c), c.req.valid("json"), viewer(c))));
63
64
  app.get(`${base}/replies`, describeRoute({
64
65
  summary: "List the canned replies.",
65
66
  verification: "control-plane",
@@ -21,7 +21,7 @@ export type ThreadIdParam = z.infer<typeof ThreadIdParam>;
21
21
  /**
22
22
  * The inbox listing query.
23
23
  *
24
- * **Strict, and there is no `q`.** Listing lists; `GET {basePath}/threads/search` searches. An unknown
24
+ * **Strict, and there is no `q`.** Listing lists; `POST {basePath}/threads/search` searches. An unknown
25
25
  * key is refused as `validation/invalid_input` rather than ignored, so a client sending `q` is told so
26
26
  * instead of getting the unfiltered inbox back as though it were the answer.
27
27
  */
@@ -60,12 +60,13 @@ export declare const SupportSearchMode: z.ZodEnum<{
60
60
  semantic: "semantic";
61
61
  }>;
62
62
  export type SupportSearchMode = z.infer<typeof SupportSearchMode>;
63
- /** The search query. */
64
- export declare const SearchThreadsQuery: z.ZodObject<{
65
- archived: z.ZodOptional<z.ZodEnum<{
66
- false: "false";
67
- true: "true";
68
- }>>;
63
+ /**
64
+ * The body of `POST {basePath}/threads/search`: the words, the mode, how many, and the inbox listing's filters.
65
+ * A body, not a query string, because the words are often a customer's address or order number and a URL is
66
+ * written to every request log between the client and the Worker. Strict, so a misspelled filter is refused
67
+ * rather than silently widening the search.
68
+ */
69
+ export declare const SearchThreadsBody: z.ZodObject<{
69
70
  category: z.ZodOptional<z.ZodString>;
70
71
  declaredCategory: z.ZodOptional<z.ZodString>;
71
72
  priority: z.ZodOptional<z.ZodEnum<{
@@ -91,9 +92,10 @@ export declare const SearchThreadsQuery: z.ZodObject<{
91
92
  keyword: "keyword";
92
93
  semantic: "semantic";
93
94
  }>>;
94
- limit: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
95
+ limit: z.ZodOptional<z.ZodNumber>;
96
+ archived: z.ZodOptional<z.ZodBoolean>;
95
97
  }, z.core.$strict>;
96
- export type SearchThreadsQuery = z.infer<typeof SearchThreadsQuery>;
98
+ export type SearchThreadsBody = z.infer<typeof SearchThreadsBody>;
97
99
  /** The archive/unarchive body. */
98
100
  export declare const ArchiveThreadInput: z.ZodObject<{
99
101
  archived: z.ZodBoolean;
@@ -1 +1 @@
1
- {"version":3,"file":"schemas.d.ts","sourceRoot":"","sources":["../../src/http/schemas.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAcxB;;;;;;;;;;;GAWG;AAEH,+BAA+B;AAC/B,eAAO,MAAM,aAAa;;iBAOsC,CAAC;AACjE,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAC;AAyC1D;;;;;;GAMG;AACH,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;kBAiBmE,CAAC;AACjG,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAEhE,yBAAyB;AACzB,eAAO,MAAM,iBAAiB;;;;EAI3B,CAAC;AACJ,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAElE,wBAAwB;AACxB,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAuBqF,CAAC;AACrH,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAEpE,kCAAkC;AAClC,eAAO,MAAM,kBAAkB;;iBAQuB,CAAC;AACvD,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAEpE,mCAAmC;AACnC,eAAO,MAAM,aAAa;;;iBAOoE,CAAC;AAC/F,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAC;AAE1D,yDAAyD;AACzD,eAAO,MAAM,yBAAyB,MAAM,CAAC;AAE7C,iGAAiG;AACjG,eAAO,MAAM,iBAAiB;;;;;;iBAeiC,CAAC;AAChE,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAElE,sBAAsB;AACtB,eAAO,MAAM,UAAU;;;iBAmB0B,CAAC;AAClD,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,UAAU,CAAC,CAAC;AAEpD,iCAAiC;AACjC,eAAO,MAAM,UAAU;;;iBAWmC,CAAC;AAC3D,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,UAAU,CAAC,CAAC;AAEpD;;;;;;;;GAQG;AACH,eAAO,MAAM,wBAAwB;;;;iBA4B8D,CAAC;AACpG,MAAM,MAAM,wBAAwB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAEhF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;iBAiCqF,CAAC;AACtH,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAEtE,uCAAuC;AACvC,eAAO,MAAM,cAAc;;;iBAiBxB,CAAC;AACJ,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AAE5D,sCAAsC;AACtC,eAAO,MAAM,YAAY;;iBAM4B,CAAC;AACtD,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,YAAY,CAAC,CAAC"}
1
+ {"version":3,"file":"schemas.d.ts","sourceRoot":"","sources":["../../src/http/schemas.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAcxB;;;;;;;;;;;GAWG;AAEH,+BAA+B;AAC/B,eAAO,MAAM,aAAa;;iBAOsC,CAAC;AACjE,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAC;AAyC1D;;;;;;GAMG;AACH,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;kBAiBmE,CAAC;AACjG,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAEhE,yBAAyB;AACzB,eAAO,MAAM,iBAAiB;;;;EAI3B,CAAC;AACJ,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAElE;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAwBsF,CAAC;AACrH,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAElE,kCAAkC;AAClC,eAAO,MAAM,kBAAkB;;iBAQuB,CAAC;AACvD,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAEpE,mCAAmC;AACnC,eAAO,MAAM,aAAa;;;iBAOoE,CAAC;AAC/F,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAC;AAE1D,yDAAyD;AACzD,eAAO,MAAM,yBAAyB,MAAM,CAAC;AAE7C,iGAAiG;AACjG,eAAO,MAAM,iBAAiB;;;;;;iBAeiC,CAAC;AAChE,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAElE,sBAAsB;AACtB,eAAO,MAAM,UAAU;;;iBAmB0B,CAAC;AAClD,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,UAAU,CAAC,CAAC;AAEpD,iCAAiC;AACjC,eAAO,MAAM,UAAU;;;iBAWmC,CAAC;AAC3D,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,UAAU,CAAC,CAAC;AAEpD;;;;;;;;GAQG;AACH,eAAO,MAAM,wBAAwB;;;;iBA4B8D,CAAC;AACpG,MAAM,MAAM,wBAAwB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAEhF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;iBAiCqF,CAAC;AACtH,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAEtE,uCAAuC;AACvC,eAAO,MAAM,cAAc;;;iBAiBxB,CAAC;AACJ,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AAE5D,sCAAsC;AACtC,eAAO,MAAM,YAAY;;iBAM4B,CAAC;AACtD,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,YAAY,CAAC,CAAC"}
@@ -6,6 +6,7 @@ import { UNASSIGNED } from "../data/assignment.js";
6
6
  import { SupportSubmissionContext } from "../data/message.js";
7
7
  import "../store/paging.js";
8
8
  import { z } from "zod";
9
+ import { freeText } from "@pithy-sh/core/src/http/freeText";
9
10
  import { PresenceParticipantName, PresenceParticipantRef } from "@pithy-sh/core/src/presence/frames";
10
11
  //#region src/http/schemas.ts
11
12
  /** An assignee reference, as the listing filters on it and an assignment names it. */
@@ -40,7 +41,7 @@ const threadFilterFields = {
40
41
  /**
41
42
  * The inbox listing query.
42
43
  *
43
- * **Strict, and there is no `q`.** Listing lists; `GET {basePath}/threads/search` searches. An unknown
44
+ * **Strict, and there is no `q`.** Listing lists; `POST {basePath}/threads/search` searches. An unknown
44
45
  * key is refused as `validation/invalid_input` rather than ignored, so a client sending `q` is told so
45
46
  * instead of getting the unfiltered inbox back as though it were the answer.
46
47
  */
@@ -55,12 +56,18 @@ const SupportSearchMode = z.enum([
55
56
  "semantic",
56
57
  "hybrid"
57
58
  ]).describe("`keyword` finds the exact words — FTS5 when `search.fts` is on, the `LIKE` scan otherwise. `semantic` finds the meaning, through the message index. `hybrid` runs both and ranks them as one.");
58
- /** The search query. */
59
- const SearchThreadsQuery = z.object({
60
- q: z.string().trim().min(1).max(200).describe("What to search for, in the customer's words or yours. An order number, an error, or a description."),
59
+ /**
60
+ * The body of `POST {basePath}/threads/search`: the words, the mode, how many, and the inbox listing's filters.
61
+ * A body, not a query string, because the words are often a customer's address or order number and a URL is
62
+ * written to every request log between the client and the Worker. Strict, so a misspelled filter is refused
63
+ * rather than silently widening the search.
64
+ */
65
+ const SearchThreadsBody = z.object({
66
+ ...threadFilterFields,
67
+ q: freeText(z.string().trim().min(1).max(200)).describe("What to search for, in the customer's words or yours. An order number, an error, or a description."),
61
68
  mode: SupportSearchMode.optional().describe("Which backends to run. Absent runs every one that is on, as `hybrid`. `semantic` or `hybrid` while `search.semantic` is off is refused, naming the flag."),
62
- limit: z.coerce.number().int().min(1).max(50).optional().describe(`How many threads to return, best first. Default 20, at most 50. No cursor: a ranked list has a top, not pages.`),
63
- ...threadFilterFields
69
+ limit: z.number().int().min(1).max(50).optional().describe(`How many threads to return, best first. Default 20, at most 50. No cursor: a ranked list has a top, not pages.`),
70
+ archived: z.boolean().optional().describe("`true` for the done pile, `false` or absent for the open inbox — which is the default on purpose.")
64
71
  }).strict().describe("A search over the inbox: the words, the mode, how many, and the same filters the inbox listing takes.");
65
72
  /** The archive/unarchive body. */
66
73
  const ArchiveThreadInput = z.object({ archived: z.boolean().describe("`true` marks the conversation done; `false` reopens it. Explicit rather than a toggle, so a retried request lands on the state the caller meant rather than flipping it back.") }).describe("Mark a conversation done, or reopen it.");
@@ -127,4 +134,4 @@ const MyThreadsQuery = z.object({
127
134
  /** The canned-reply catalog query. */
128
135
  const RepliesQuery = z.object({ category: CategoryFilter.optional().describe("Order the catalog for this category — its snippets first, then the general-purpose ones. Ordering, never filtering: a misclassified thread must not hide the snippet its operator actually needs.") }).describe("How to order the canned reply catalog.");
129
136
  //#endregion
130
- export { ArchiveThreadInput, AssignThreadInput, AssigneeInput, FlagsInput, ListThreadsQuery, MAX_ASSIGNMENT_NOTE_CHARS, MyThreadsQuery, RepliesQuery, ReplyInput, SearchThreadsQuery, SubmitFeedbackInput, SubmittedAttachmentInput, SupportSearchMode, ThreadIdParam };
137
+ export { ArchiveThreadInput, AssignThreadInput, AssigneeInput, FlagsInput, ListThreadsQuery, MAX_ASSIGNMENT_NOTE_CHARS, MyThreadsQuery, RepliesQuery, ReplyInput, SearchThreadsBody, SubmitFeedbackInput, SubmittedAttachmentInput, SupportSearchMode, ThreadIdParam };
@@ -1 +1 @@
1
- {"version":3,"file":"scopes.d.ts","sourceRoot":"","sources":["../../src/http/scopes.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,sDAAsD,CAAC;AAClG,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,6CAA6C,CAAC;AAErF;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,iGAAiG;AACjG,eAAO,MAAM,0BAA0B,EAAE,iBAA0C,CAAC;AAEpF,oFAAoF;AACpF,eAAO,MAAM,6BAA6B,EAAE,iBAA6C,CAAC;AAE1F;;;GAGG;AACH,eAAO,MAAM,2BAA2B,EAAE,iBAA2C,CAAC;AAEtF,8EAA8E;AAC9E,eAAO,MAAM,gCAAgC,EAAE,iBAAgD,CAAC;AAEhG,wGAAwG;AACxG,eAAO,MAAM,0BAA0B,EAAE,iBAA0C,CAAC;AAEpF;;;GAGG;AACH,eAAO,MAAM,4BAA4B,EAAE,iBAA4C,CAAC;AAExF;;;GAGG;AACH,eAAO,MAAM,4BAA4B,EAAE,SAAS,iBAAiB,EAOpE,CAAC;AAEF;;;;;;;;;;GAUG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,qBAAqB,EAAE,CA2E5E"}
1
+ {"version":3,"file":"scopes.d.ts","sourceRoot":"","sources":["../../src/http/scopes.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,sDAAsD,CAAC;AAClG,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,6CAA6C,CAAC;AAErF;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,iGAAiG;AACjG,eAAO,MAAM,0BAA0B,EAAE,iBAA0C,CAAC;AAEpF,oFAAoF;AACpF,eAAO,MAAM,6BAA6B,EAAE,iBAA6C,CAAC;AAE1F;;;GAGG;AACH,eAAO,MAAM,2BAA2B,EAAE,iBAA2C,CAAC;AAEtF,8EAA8E;AAC9E,eAAO,MAAM,gCAAgC,EAAE,iBAAgD,CAAC;AAEhG,wGAAwG;AACxG,eAAO,MAAM,0BAA0B,EAAE,iBAA0C,CAAC;AAEpF;;;GAGG;AACH,eAAO,MAAM,4BAA4B,EAAE,iBAA4C,CAAC;AAExF;;;GAGG;AACH,eAAO,MAAM,4BAA4B,EAAE,SAAS,iBAAiB,EAOpE,CAAC;AAEF;;;;;;;;;;GAUG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,qBAAqB,EAAE,CA4E5E"}
@@ -76,11 +76,12 @@ function supportAdminRoutes(basePath) {
76
76
  summary: "List the inbox, newest first, filtered by category, priority, assignee, and archived."
77
77
  },
78
78
  {
79
- method: "GET",
79
+ method: "POST",
80
80
  operation: "threads.search",
81
81
  path: `${basePath}/threads/search`,
82
82
  scope: SUPPORT_THREADS_READ_SCOPE,
83
83
  kind: "reads",
84
+ readInBody: true,
84
85
  summary: "Search the inbox by words and by meaning, ranked as one, with the same filters as the list."
85
86
  },
86
87
  {
@@ -66,7 +66,7 @@ export interface ThreadFilters {
66
66
  /**
67
67
  * What a caller may filter the inbox by, and where to resume.
68
68
  *
69
- * **No free text.** Listing lists; `GET {basePath}/threads/search` searches, ranked, with a limit and no
69
+ * **No free text.** Listing lists; `POST {basePath}/threads/search` searches, ranked, with a limit and no
70
70
  * cursor. A `q` here could say whether a thread matched, never how well.
71
71
  */
72
72
  export interface ListThreadsQuery extends ThreadFilters {
@@ -3,5 +3,5 @@
3
3
  /** This package's npm name — the join key against a release feed. */
4
4
  export declare const PACKAGE_NAME = "@pithy-sh/support";
5
5
  /** This package's version, stamped from its own package.json at generation time. */
6
- export declare const PACKAGE_VERSION = "0.7.0";
6
+ export declare const PACKAGE_VERSION = "0.8.0";
7
7
  //# sourceMappingURL=version.generated.d.ts.map
@@ -4,6 +4,6 @@
4
4
  /** This package's npm name — the join key against a release feed. */
5
5
  const PACKAGE_NAME = "@pithy-sh/support";
6
6
  /** This package's version, stamped from its own package.json at generation time. */
7
- const PACKAGE_VERSION = "0.7.0";
7
+ const PACKAGE_VERSION = "0.8.0";
8
8
  //#endregion
9
9
  export { PACKAGE_NAME, PACKAGE_VERSION };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pithy-sh/support",
3
- "version": "0.7.0",
3
+ "version": "0.8.0",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
@@ -40,13 +40,13 @@
40
40
  "tldts": "^7.4.10"
41
41
  },
42
42
  "peerDependencies": {
43
- "@pithy-sh/auth": "^0.13.0",
44
- "@pithy-sh/core": "^0.17.0",
45
- "@pithy-sh/email": "^0.9.0",
46
- "@pithy-sh/payments": "^0.8.0",
47
- "@pithy-sh/secrets": "^0.6.5",
48
- "@pithy-sh/storage": "^0.7.3",
49
- "@pithy-sh/vector": "^0.5.5",
43
+ "@pithy-sh/auth": "^0.14.0",
44
+ "@pithy-sh/core": "^0.18.0",
45
+ "@pithy-sh/email": "^0.10.0",
46
+ "@pithy-sh/payments": "^0.8.1",
47
+ "@pithy-sh/secrets": "^0.6.6",
48
+ "@pithy-sh/storage": "^0.7.4",
49
+ "@pithy-sh/vector": "^0.5.6",
50
50
  "hono": "^4.13.2",
51
51
  "kysely": "^0.29.0",
52
52
  "zod": "^4.4.0"
@@ -45,7 +45,7 @@
45
45
  "If your feedback screen offers a chooser, send its answer as `declaredCategory`. It lands in its own column beside `category` and is never overwritten by the classifier — one is a claim by the person writing, the other a judgement about them, and an operator triaging an inbox needs to tell them apart. `GET /support/threads` filters on either. A key outside your taxonomy is refused rather than stored, and a category sent with a `threadId` is refused too: a chooser belongs on the form that opens a request.",
46
46
  "`POST /support/feedback` is gated on a session and same-origin and never on a role — a general intake that is role-gated is not one. If your own account model makes some submissions act-on-behalf-of, put that check in your `app` capability's `middleware` over your own `basePath`: every capability's middleware mounts before any capability's routes, so yours runs after auth has resolved the session and before this capability's `requireAuth()`.",
47
47
  "If your own signed-in users work the inbox, name two powers in `support({ staff: { readPower, assignPower } })` and give them to a role in your organization catalog's `unassignable` list that `organization({ ownership })` does not confer, so only an operator can confer them — anybody may found an organization and take its ownership role, so `support()` refuses a staff power there. `readPower` lets a staff member join a thread's presence room; `assignPower` lets them assign it at `POST /support/staff/threads/:id/assign`. Without `staff`, both answer to management clients only.",
48
- "Search the inbox at `GET /support/threads/search` — keyword by default, ranked; the inbox list takes no `q`. Turn on `search: { semantic: true }` to find a paraphrase as well as an exact word: it embeds every inbound message on your own Workers AI binding, a second inference per message on top of classification, so it is off until you choose it. Then run `pithy support provision`, which creates the Vectorize index, binds it, and backfills it once; `pithy vector reprocess --index support-messages` re-embeds after a model change.",
48
+ "Search the inbox at `POST /support/threads/search`, with the words and the filters in a JSON body, so a customer's address typed into the box never lands in a request log — keyword by default, ranked; the inbox list takes no `q`. Turn on `search: { semantic: true }` to find a paraphrase as well as an exact word: it embeds every inbound message on your own Workers AI binding, a second inference per message on top of classification, so it is off until you choose it. Then run `pithy support provision`, which creates the Vectorize index, binds it, and backfills it once; `pithy vector reprocess --index support-messages` re-embeds after a model change.",
49
49
  "Run `pithy support provision` after adding support or upgrading it: `search.fts` is on by default, and the FTS5 index and its triggers are provisioned rather than migrated. Until then search falls back to a `LIKE` scan and `pithy doctor` names the environment. Back the database up with `pithy backup`, which skips the index, and restore it with `pithy restore`, which rebuilds it — a plain `wrangler d1 export` fails on any database holding an FTS5 table."
50
50
  ],
51
51
  "configOptions": [
@@ -56,7 +56,7 @@ import type {
56
56
  MyThreadsQuery,
57
57
  RepliesQuery,
58
58
  ReplyInput,
59
- SearchThreadsQuery,
59
+ SearchThreadsBody,
60
60
  SubmitFeedbackInput,
61
61
  } from "./schemas";
62
62
  import {
@@ -148,7 +148,7 @@ export async function listInbox(
148
148
  */
149
149
  export async function searchInbox(
150
150
  deps: HandlerDeps,
151
- query: SearchThreadsQuery,
151
+ query: SearchThreadsBody,
152
152
  viewer: string,
153
153
  ): Promise<SupportSearchResponse> {
154
154
  const outcome = await searchThreads(
@@ -165,7 +165,7 @@ export async function searchInbox(
165
165
  q: query.q,
166
166
  ...(query.mode !== undefined ? { mode: query.mode } : {}),
167
167
  ...(query.limit !== undefined ? { limit: query.limit } : {}),
168
- archived: query.archived === "true",
168
+ archived: query.archived === true,
169
169
  category: query.category,
170
170
  declaredCategory: query.declaredCategory,
171
171
  priority: query.priority,
@@ -34,16 +34,14 @@ import { SupportSubmissionContext } from "../data/message";
34
34
  *
35
35
  * **A browser imports this file, so it reaches no module that needs the Workers runtime.** That is not
36
36
  * a preference about bundle size; it is what "a client validates what comes back" means once the client
37
- * is a Vite program with the DOM lib and no Workers types. This file imported `SUPPORT_BILLING_SCOPE`
38
- * from `link/sender.ts` for one release and brought D1, Kysely and two capabilities' table maps with it,
39
- * which took `pithy-sh/dashboard`'s client build down on an error in `@pithy-sh/auth` (#419). The rule is
40
- * held by `tooling/browser-scopes`, which compiles this module with `types: []` and asks the compiler
37
+ * is a Vite program with the DOM lib and no Workers types: an import of `link/sender.ts` would bring D1,
38
+ * Kysely and two capabilities' table maps into that build. The rule is held by `tooling/browser-scopes`, which compiles this module with `types: []` and asks the compiler
41
39
  * which files that program included.
42
40
  *
43
41
  * **A field added here later is `.optional()`, not merely `.nullable()`.** This module is read across a
44
42
  * version boundary — a management client validates a response with this schema against a customer's
45
43
  * Worker at whatever kit version it is on — so an additive required key fails `safeParse` for everyone
46
- * below that release and takes the whole pane with it (#450). Absent then means *this Worker cannot
44
+ * below that release and takes the whole pane with it. Absent then means *this Worker cannot
47
45
  * say*, which is a different fact from `null`.
48
46
  */
49
47
 
@@ -110,7 +108,7 @@ export const SupportThreadView = z
110
108
  .describe(
111
109
  "The control-plane subject that archived it, for convenience only — the answer to 'who marked this done' comes from the audit trail.",
112
110
  ),
113
- // Optional as well as nullable (#450, #816): absent says *this Worker predates assignment*, which a client
111
+ // Optional as well as nullable: absent says *this Worker predates assignment*, which a client
114
112
  // must not read as *nobody has it*.
115
113
  assigneeRef: z
116
114
  .string()
@@ -346,7 +344,7 @@ export const SupportSearchResultView = z
346
344
  .describe("One thread a search found, named by its best-matching message, with that message's raw scores.");
347
345
  export type SupportSearchResultView = z.output<typeof SupportSearchResultView>;
348
346
 
349
- /** `GET {base}/threads/search`. */
347
+ /** `POST {base}/threads/search`. */
350
348
  export const SupportSearchResponse = z
351
349
  .object({
352
350
  mode: z
@@ -418,7 +416,7 @@ export const SupportThreadResponse = z
418
416
  .describe("Its attachments, across every message, each naming the message it arrived on in `messageId`."),
419
417
  sender: SenderContextView.describe("What the app already knows about the sender."),
420
418
  replies: z.array(SupportReplyView).describe("The canned replies, ordered for this thread's category."),
421
- // Optional (#450): absent from a Worker that predates assignment.
419
+ // Optional: absent from a Worker that predates assignment.
422
420
  assignments: z
423
421
  .array(SupportAssignmentView)
424
422
  .optional()
@@ -518,9 +516,8 @@ export type SupportFlagsResponse = z.output<typeof SupportFlagsResponse>;
518
516
  * Below is the same projection for the other consumer: a management client reading a Worker **it does
519
517
  * not control**. That client is crossing a trust boundary — a fork, a bug, a half-finished deploy, or a
520
518
  * hostile Worker each put a member here that no enum of ours declares — and under the strict schema one
521
- * such token costs it the entire response. It cost `pithy-sh/dashboard#15` exactly that: one
522
- * unrecognized `channel` and the support pane rendered zero of twenty-five conversations. The client
523
- * then had to widen our shape locally, which is the hand-held mirror `#113` exists to forbid.
519
+ * such token costs it the entire response: one unrecognized `channel` and a support pane renders none of
520
+ * its conversations, and the client is left widening our shape locally, the hand-held mirror the kit forbids.
524
521
  *
525
522
  * So the tolerance is published rather than reimplemented, by the one pattern
526
523
  * `@pithy-sh/core/src/projection/asRead` states for the whole kit: same objects, every enum read as a
@@ -553,7 +550,7 @@ export type SupportMessageViewAsRead = z.output<typeof SupportMessageViewAsRead>
553
550
  export const SupportThreadsResponseAsRead = asRead(SupportThreadsResponse);
554
551
  export type SupportThreadsResponseAsRead = z.output<typeof SupportThreadsResponseAsRead>;
555
552
 
556
- /** `GET {base}/threads/search`, as a client that does not control the Worker must read it. */
553
+ /** `POST {base}/threads/search`, as a client that does not control the Worker must read it. */
557
554
  export const SupportSearchResponseAsRead = asRead(SupportSearchResponse);
558
555
  export type SupportSearchResponseAsRead = z.output<typeof SupportSearchResponseAsRead>;
559
556
 
@@ -47,7 +47,7 @@ import {
47
47
  MyThreadsQuery,
48
48
  RepliesQuery,
49
49
  ReplyInput,
50
- SearchThreadsQuery,
50
+ SearchThreadsBody,
51
51
  SubmitFeedbackInput,
52
52
  ThreadIdParam,
53
53
  } from "./schemas";
@@ -64,7 +64,7 @@ import {
64
64
  * The support routes, their verification strategies, and what each accepts:
65
65
  *
66
66
  * GET /support/threads → the inbox (control-plane: support:threads:read) query: ListThreadsQuery
67
- * GET /support/threads/search → search (control-plane: support:threads:read) query: SearchThreadsQuery
67
+ * POST /support/threads/search → search (control-plane: support:threads:read) json: SearchThreadsBody
68
68
  * GET /support/threads/:id → one thread (control-plane: support:threads:read) param: ThreadIdParam
69
69
  * POST /support/threads/:id/archive → done/reopen (control-plane: support:threads:archive) param + json
70
70
  * POST /support/threads/:id/assign → who has it (control-plane: support:threads:assign) param + json
@@ -114,8 +114,8 @@ import {
114
114
  * person who most needs to reach support is often the one whose access is broken, and a role the kit
115
115
  * invented would make one adopter's account model a condition on everybody's ability to report a bug.
116
116
  *
117
- * But an adopter whose *own* model makes some submissions act-on-behalf-of — `pithy-sh/dashboard#10`'s
118
- * discount application is made for an organization, and a member may not make one — needs somewhere to
117
+ * But an adopter whose *own* model makes some submissions act-on-behalf-of — a discount application made
118
+ * for an organization, which a member may not make — needs somewhere to
119
119
  * put that check, and it must not be the client. **The seam for it already exists, in the composition
120
120
  * contract rather than in this capability's config**, and it is documented here because it was not
121
121
  * discoverable rather than because it was missing:
@@ -238,18 +238,19 @@ export function registerSupportRoutes(options: SupportRoutesOptions): (app: Hono
238
238
  async (c) => c.json(await listInbox(await resolve(c), c.req.valid("query"), viewer(c))),
239
239
  );
240
240
 
241
- // Before `/threads/:id`, so `search` is never read as a thread id.
242
- app.get(
241
+ app.post(
243
242
  `${base}/threads/search`,
244
243
  describeRoute({
245
244
  summary: "Search the inbox, by words and by meaning, ranked as one.",
245
+ description:
246
+ "The words travel in the body, because they are often a customer's address or order number and a query string is written to every request log between the client and the Worker. Read-only.",
246
247
  verification: "control-plane",
247
248
  scopes: [SUPPORT_THREADS_READ_SCOPE],
248
249
  responses: { 200: SupportSearchResponse },
249
250
  }),
250
251
  requireControlPlane(SUPPORT_THREADS_READ_SCOPE),
251
- validate("query", SearchThreadsQuery),
252
- async (c) => c.json(await searchInbox(await resolve(c), c.req.valid("query"), viewer(c))),
252
+ validate("json", SearchThreadsBody),
253
+ async (c) => c.json(await searchInbox(await resolve(c), c.req.valid("json"), viewer(c))),
253
254
  );
254
255
 
255
256
  app.get(
@@ -1,6 +1,7 @@
1
1
  // SPDX-FileCopyrightText: 2026 Pithy
2
2
  // SPDX-License-Identifier: MIT
3
3
 
4
+ import { freeText } from "@pithy-sh/core/src/http/freeText";
4
5
  import { PresenceParticipantName, PresenceParticipantRef } from "@pithy-sh/core/src/presence/frames";
5
6
  import { z } from "zod";
6
7
  import { MAX_SUBMISSION_ATTACHMENTS, MAX_SUBMISSION_BODY_CHARS, MAX_SUBMISSION_SUBJECT_CHARS } from "../config/config";
@@ -82,7 +83,7 @@ const threadFilterFields = {
82
83
  /**
83
84
  * The inbox listing query.
84
85
  *
85
- * **Strict, and there is no `q`.** Listing lists; `GET {basePath}/threads/search` searches. An unknown
86
+ * **Strict, and there is no `q`.** Listing lists; `POST {basePath}/threads/search` searches. An unknown
86
87
  * key is refused as `validation/invalid_input` rather than ignored, so a client sending `q` is told so
87
88
  * instead of getting the unfiltered inbox back as though it were the answer.
88
89
  */
@@ -114,19 +115,22 @@ export const SupportSearchMode = z
114
115
  );
115
116
  export type SupportSearchMode = z.infer<typeof SupportSearchMode>;
116
117
 
117
- /** The search query. */
118
- export const SearchThreadsQuery = z
118
+ /**
119
+ * The body of `POST {basePath}/threads/search`: the words, the mode, how many, and the inbox listing's filters.
120
+ * A body, not a query string, because the words are often a customer's address or order number and a URL is
121
+ * written to every request log between the client and the Worker. Strict, so a misspelled filter is refused
122
+ * rather than silently widening the search.
123
+ */
124
+ export const SearchThreadsBody = z
119
125
  .object({
120
- q: z
121
- .string()
122
- .trim()
123
- .min(1)
124
- .max(MAX_SEARCH_TERM)
125
- .describe("What to search for, in the customer's words or yours. An order number, an error, or a description."),
126
+ ...threadFilterFields,
127
+ q: freeText(z.string().trim().min(1).max(MAX_SEARCH_TERM)).describe(
128
+ "What to search for, in the customer's words or yours. An order number, an error, or a description.",
129
+ ),
126
130
  mode: SupportSearchMode.optional().describe(
127
131
  "Which backends to run. Absent runs every one that is on, as `hybrid`. `semantic` or `hybrid` while `search.semantic` is off is refused, naming the flag.",
128
132
  ),
129
- limit: z.coerce
133
+ limit: z
130
134
  .number()
131
135
  .int()
132
136
  .min(1)
@@ -135,11 +139,14 @@ export const SearchThreadsQuery = z
135
139
  .describe(
136
140
  `How many threads to return, best first. Default ${DEFAULT_SEARCH_LIMIT}, at most ${MAX_SEARCH_LIMIT}. No cursor: a ranked list has a top, not pages.`,
137
141
  ),
138
- ...threadFilterFields,
142
+ archived: z
143
+ .boolean()
144
+ .optional()
145
+ .describe("`true` for the done pile, `false` or absent for the open inbox — which is the default on purpose."),
139
146
  })
140
147
  .strict()
141
148
  .describe("A search over the inbox: the words, the mode, how many, and the same filters the inbox listing takes.");
142
- export type SearchThreadsQuery = z.infer<typeof SearchThreadsQuery>;
149
+ export type SearchThreadsBody = z.infer<typeof SearchThreadsBody>;
143
150
 
144
151
  /** The archive/unarchive body. */
145
152
  export const ArchiveThreadInput = z
@@ -87,11 +87,12 @@ export function supportAdminRoutes(basePath: string): AdminRouteDeclaration[] {
87
87
  summary: "List the inbox, newest first, filtered by category, priority, assignee, and archived.",
88
88
  },
89
89
  {
90
- method: "GET",
90
+ method: "POST",
91
91
  operation: "threads.search",
92
92
  path: `${basePath}/threads/search`,
93
93
  scope: SUPPORT_THREADS_READ_SCOPE,
94
94
  kind: "reads",
95
+ readInBody: true,
95
96
  summary: "Search the inbox by words and by meaning, ranked as one, with the same filters as the list.",
96
97
  },
97
98
  {
@@ -97,7 +97,7 @@ export interface ThreadFilters {
97
97
  /**
98
98
  * What a caller may filter the inbox by, and where to resume.
99
99
  *
100
- * **No free text.** Listing lists; `GET {basePath}/threads/search` searches, ranked, with a limit and no
100
+ * **No free text.** Listing lists; `POST {basePath}/threads/search` searches, ranked, with a limit and no
101
101
  * cursor. A `q` here could say whether a thread matched, never how well.
102
102
  */
103
103
  export interface ListThreadsQuery extends ThreadFilters {
@@ -13,4 +13,4 @@
13
13
  export const PACKAGE_NAME = "@pithy-sh/support";
14
14
 
15
15
  /** This package's version, stamped from its own package.json at generation time. */
16
- export const PACKAGE_VERSION = "0.7.0";
16
+ export const PACKAGE_VERSION = "0.8.0";