@ecency/sdk 2.4.15 → 2.4.17

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 (45) hide show
  1. package/dist/browser/{chunk-WTEHM2NW.js → chunk-AGRX3S2G.js} +2 -2
  2. package/dist/browser/{chunk-WTEHM2NW.js.map → chunk-AGRX3S2G.js.map} +1 -1
  3. package/dist/browser/{chunk-O6ZNF26Q.js → chunk-AZR63GSQ.js} +2 -2
  4. package/dist/browser/{chunk-O6ZNF26Q.js.map → chunk-AZR63GSQ.js.map} +1 -1
  5. package/dist/browser/{chunk-VP72GHX2.js → chunk-E6UOGKIO.js} +2 -2
  6. package/dist/browser/{chunk-VP72GHX2.js.map → chunk-E6UOGKIO.js.map} +1 -1
  7. package/dist/browser/{chunk-UPLGU6G7.js → chunk-F6NBFXMD.js} +2 -2
  8. package/dist/browser/{chunk-UPLGU6G7.js.map → chunk-F6NBFXMD.js.map} +1 -1
  9. package/dist/browser/chunk-HBIRNFVS.js +2 -0
  10. package/dist/browser/chunk-HBIRNFVS.js.map +1 -0
  11. package/dist/browser/{chunk-A7EC46DB.js → chunk-IZAIV6WY.js} +2 -2
  12. package/dist/browser/{chunk-A7EC46DB.js.map → chunk-IZAIV6WY.js.map} +1 -1
  13. package/dist/browser/{chunk-LM7BVTOQ.js → chunk-JQBX6M24.js} +2 -2
  14. package/dist/browser/{chunk-LM7BVTOQ.js.map → chunk-JQBX6M24.js.map} +1 -1
  15. package/dist/browser/{chunk-RYI4O7QH.js → chunk-KSQXXIUM.js} +2 -2
  16. package/dist/browser/{chunk-RYI4O7QH.js.map → chunk-KSQXXIUM.js.map} +1 -1
  17. package/dist/browser/{chunk-ZKWRPZHK.js → chunk-R4TN3IDN.js} +2 -2
  18. package/dist/browser/{chunk-ZKWRPZHK.js.map → chunk-R4TN3IDN.js.map} +1 -1
  19. package/dist/browser/{chunk-ISEY5355.js → chunk-Y2O7DW46.js} +2 -2
  20. package/dist/browser/{chunk-ISEY5355.js.map → chunk-Y2O7DW46.js.map} +1 -1
  21. package/dist/browser/chunk-ZLU6INZR.js +2 -0
  22. package/dist/browser/{chunk-WAIGSUA6.js.map → chunk-ZLU6INZR.js.map} +1 -1
  23. package/dist/browser/index.d.ts +70 -5
  24. package/dist/browser/index.js +1 -1
  25. package/dist/browser/modules/curation/index.js +1 -1
  26. package/dist/browser/modules/curation/queries/get-curation-application-query-options.js +1 -1
  27. package/dist/browser/modules/curation/queries/get-curation-applications-query-options.js +1 -1
  28. package/dist/browser/modules/curation/queries/get-curation-feed-infinite-query-options.js +1 -1
  29. package/dist/browser/modules/curation/queries/get-curation-post-query-options.js +1 -1
  30. package/dist/browser/modules/curation/queries/get-curation-recommendations-infinite-query-options.js +1 -1
  31. package/dist/browser/modules/curation/queries/get-curation-recommender-query-options.js +1 -1
  32. package/dist/browser/modules/curation/queries/get-curation-roster-admin-query-options.js +1 -1
  33. package/dist/browser/modules/curation/queries/get-curation-roster-query-options.js +1 -1
  34. package/dist/browser/modules/curation/queries/get-curation-status-query-options.js +1 -1
  35. package/dist/browser/modules/curation/queries/index.js +1 -1
  36. package/dist/browser/modules/curation/requests.js +1 -1
  37. package/dist/browser/modules/curation/types.js +1 -1
  38. package/dist/node/index.cjs +3 -3
  39. package/dist/node/index.cjs.map +1 -1
  40. package/dist/node/index.mjs +3 -3
  41. package/dist/node/index.mjs.map +1 -1
  42. package/package.json +1 -1
  43. package/dist/browser/chunk-4DTETBSG.js +0 -2
  44. package/dist/browser/chunk-4DTETBSG.js.map +0 -1
  45. package/dist/browser/chunk-WAIGSUA6.js +0 -2
@@ -1,2 +1,2 @@
1
- import {q}from'./chunk-4DTETBSG.js';import {a}from'./chunk-HEILHNSR.js';import {queryOptions}from'@tanstack/react-query';function c(i,t,n){return queryOptions({queryKey:a.curation.applications(i,n),queryFn:({signal:o})=>{if(!i||!t)throw new Error("[SDK][Curation] reading the application queue needs a signed-in account");return q(t,{state:n},o)},enabled:!!i&&!!t,staleTime:6e4})}export{c as a};//# sourceMappingURL=chunk-WTEHM2NW.js.map
2
- //# sourceMappingURL=chunk-WTEHM2NW.js.map
1
+ import {q}from'./chunk-HBIRNFVS.js';import {a}from'./chunk-HEILHNSR.js';import {queryOptions}from'@tanstack/react-query';function c(i,t,n){return queryOptions({queryKey:a.curation.applications(i,n),queryFn:({signal:o})=>{if(!i||!t)throw new Error("[SDK][Curation] reading the application queue needs a signed-in account");return q(t,{state:n},o)},enabled:!!i&&!!t,staleTime:6e4})}export{c as a};//# sourceMappingURL=chunk-AGRX3S2G.js.map
2
+ //# sourceMappingURL=chunk-AGRX3S2G.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/modules/curation/queries/get-curation-applications-query-options.ts"],"names":["getCurationApplicationsQueryOptions","username","code","state","queryOptions","QueryKeys","signal","curationApplicationListRequest"],"mappings":"yHAUO,SAASA,CAAAA,CACdC,CAAAA,CACAC,CAAAA,CACAC,CAAAA,CACA,CACA,OAAOC,YAAAA,CAAa,CAClB,QAAA,CAAUC,EAAU,QAAA,CAAS,YAAA,CAAaJ,CAAAA,CAAUE,CAAK,CAAA,CACzD,OAAA,CAAS,CAAC,CAAE,MAAA,CAAAG,CAAO,CAAA,GAAM,CAGvB,GAAI,CAACL,GAAY,CAACC,CAAAA,CAChB,MAAM,IAAI,KAAA,CACR,yEACF,CAAA,CAEF,OAAOK,CAAAA,CAA+BL,CAAAA,CAAM,CAAE,KAAA,CAAAC,CAAM,CAAA,CAAGG,CAAM,CAC/D,CAAA,CACA,OAAA,CAAS,CAAC,CAACL,CAAAA,EAAY,CAAC,CAACC,CAAAA,CACzB,SAAA,CAAW,GACb,CAAC,CACH","file":"chunk-WTEHM2NW.js","sourcesContent":["import { queryOptions } from \"@tanstack/react-query\";\nimport { QueryKeys } from \"@/modules/core\";\nimport type { CurationApplicationState } from \"../types\";\nimport { curationApplicationListRequest } from \"../requests\";\n\n/**\n * The review queue. Admin only upstream, so it is keyed by the viewer and never\n * shares an entry with anything public. No state asked for means the live queue:\n * what is still waiting on a decision, oldest first.\n */\nexport function getCurationApplicationsQueryOptions(\n username: string | undefined,\n code: string | undefined,\n state?: CurationApplicationState,\n) {\n return queryOptions({\n queryKey: QueryKeys.curation.applications(username, state),\n queryFn: ({ signal }) => {\n // Guarded twice: `enabled` gates automatic fetching only, a prefetch or a\n // fetchQuery still runs this, and the request would throw \"missing auth\".\n if (!username || !code) {\n throw new Error(\n \"[SDK][Curation] reading the application queue needs a signed-in account\",\n );\n }\n return curationApplicationListRequest(code, { state }, signal);\n },\n enabled: !!username && !!code,\n staleTime: 60_000,\n });\n}\n"]}
1
+ {"version":3,"sources":["../../src/modules/curation/queries/get-curation-applications-query-options.ts"],"names":["getCurationApplicationsQueryOptions","username","code","state","queryOptions","QueryKeys","signal","curationApplicationListRequest"],"mappings":"yHAUO,SAASA,CAAAA,CACdC,CAAAA,CACAC,CAAAA,CACAC,CAAAA,CACA,CACA,OAAOC,YAAAA,CAAa,CAClB,QAAA,CAAUC,EAAU,QAAA,CAAS,YAAA,CAAaJ,CAAAA,CAAUE,CAAK,CAAA,CACzD,OAAA,CAAS,CAAC,CAAE,MAAA,CAAAG,CAAO,CAAA,GAAM,CAGvB,GAAI,CAACL,GAAY,CAACC,CAAAA,CAChB,MAAM,IAAI,KAAA,CACR,yEACF,CAAA,CAEF,OAAOK,CAAAA,CAA+BL,CAAAA,CAAM,CAAE,KAAA,CAAAC,CAAM,CAAA,CAAGG,CAAM,CAC/D,CAAA,CACA,OAAA,CAAS,CAAC,CAACL,CAAAA,EAAY,CAAC,CAACC,CAAAA,CACzB,SAAA,CAAW,GACb,CAAC,CACH","file":"chunk-AGRX3S2G.js","sourcesContent":["import { queryOptions } from \"@tanstack/react-query\";\nimport { QueryKeys } from \"@/modules/core\";\nimport type { CurationApplicationState } from \"../types\";\nimport { curationApplicationListRequest } from \"../requests\";\n\n/**\n * The review queue. Admin only upstream, so it is keyed by the viewer and never\n * shares an entry with anything public. No state asked for means the live queue:\n * what is still waiting on a decision, oldest first.\n */\nexport function getCurationApplicationsQueryOptions(\n username: string | undefined,\n code: string | undefined,\n state?: CurationApplicationState,\n) {\n return queryOptions({\n queryKey: QueryKeys.curation.applications(username, state),\n queryFn: ({ signal }) => {\n // Guarded twice: `enabled` gates automatic fetching only, a prefetch or a\n // fetchQuery still runs this, and the request would throw \"missing auth\".\n if (!username || !code) {\n throw new Error(\n \"[SDK][Curation] reading the application queue needs a signed-in account\",\n );\n }\n return curationApplicationListRequest(code, { state }, signal);\n },\n enabled: !!username && !!code,\n staleTime: 60_000,\n });\n}\n"]}
@@ -1,2 +1,2 @@
1
- import {c as c$2}from'./chunk-ISEY5355.js';import {f}from'./chunk-4DTETBSG.js';import {c as c$1}from'./chunk-YNRDVQAQ.js';import {a}from'./chunk-HEILHNSR.js';import {infiniteQueryOptions}from'@tanstack/react-query';var c=25;function R(i={}){let r=i.sort??"unique",t=i.limit??c,u={sort:r,limit:String(t)};return infiniteQueryOptions({queryKey:a.curation.recommendations(u),initialPageParam:void 0,queryFn:({pageParam:e,signal:n})=>f({sort:r,limit:t},e,n),getNextPageParam:e=>!e||e.items.length<t?void 0:e.items[e.items.length-1]?._cursor??e.next_cursor??void 0,select:e=>c$1(c$2(e,n=>`${n.author}/${n.permlink}`)),staleTime:1e4})}export{c as a,R as b};//# sourceMappingURL=chunk-O6ZNF26Q.js.map
2
- //# sourceMappingURL=chunk-O6ZNF26Q.js.map
1
+ import {c as c$2}from'./chunk-Y2O7DW46.js';import {f}from'./chunk-HBIRNFVS.js';import {c as c$1}from'./chunk-YNRDVQAQ.js';import {a}from'./chunk-HEILHNSR.js';import {infiniteQueryOptions}from'@tanstack/react-query';var c=25;function R(i={}){let r=i.sort??"unique",t=i.limit??c,u={sort:r,limit:String(t)};return infiniteQueryOptions({queryKey:a.curation.recommendations(u),initialPageParam:void 0,queryFn:({pageParam:e,signal:n})=>f({sort:r,limit:t},e,n),getNextPageParam:e=>!e||e.items.length<t?void 0:e.items[e.items.length-1]?._cursor??e.next_cursor??void 0,select:e=>c$1(c$2(e,n=>`${n.author}/${n.permlink}`)),staleTime:1e4})}export{c as a,R as b};//# sourceMappingURL=chunk-AZR63GSQ.js.map
2
+ //# sourceMappingURL=chunk-AZR63GSQ.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/modules/curation/queries/get-curation-recommendations-infinite-query-options.ts"],"names":["CURATION_RECOMMENDATIONS_PAGE_SIZE","getCurationRecommendationsInfiniteQueryOptions","params","sort","limit","normalized","infiniteQueryOptions","QueryKeys","pageParam","signal","fetchCurationRecommendationsPage","lastPage","data","maskDmcaCurationPages","dedupePagesBy","item"],"mappings":"uNAOO,IAAMA,EAAqC,GAM3C,SAASC,EACdC,CAAAA,CAAwC,GACxC,CACA,IAAMC,EAAOD,CAAAA,CAAO,IAAA,EAAQ,SACtBE,CAAAA,CAAQF,CAAAA,CAAO,KAAA,EAASF,CAAAA,CACxBK,CAAAA,CAAqC,CAAE,KAAAF,CAAAA,CAAM,KAAA,CAAO,OAAOC,CAAK,CAAE,EAExE,OAAOE,oBAAAA,CAAqB,CAC1B,QAAA,CAAUC,CAAAA,CAAU,SAAS,eAAA,CAAgBF,CAAU,EACvD,gBAAA,CAAkB,MAAA,CAClB,QAAS,CAAC,CAAE,SAAA,CAAAG,CAAAA,CAAW,MAAA,CAAAC,CAAO,IAC5BC,CAAAA,CAAiC,CAAE,KAAAP,CAAAA,CAAM,KAAA,CAAAC,CAAM,CAAA,CAAGI,CAAAA,CAAWC,CAAM,CAAA,CACrE,gBAAA,CAAmBE,GACb,CAACA,CAAAA,EAAYA,EAAS,KAAA,CAAM,MAAA,CAASP,EACvC,MAAA,CAEWO,CAAAA,CAAS,KAAA,CAAMA,CAAAA,CAAS,KAAA,CAAM,MAAA,CAAS,CAAC,CAAA,EACxC,OAAA,EAAWA,EAAS,WAAA,EAAe,MAAA,CAGlD,OAASC,CAAAA,EACPC,GAAAA,CAAsBC,GAAAA,CAAcF,CAAAA,CAAOG,CAAAA,EAAS,CAAA,EAAGA,EAAK,MAAM,CAAA,CAAA,EAAIA,EAAK,QAAQ,CAAA,CAAE,CAAC,CAAA,CACxF,SAAA,CAAW,GACb,CAAC,CACH","file":"chunk-O6ZNF26Q.js","sourcesContent":["import { infiniteQueryOptions } from \"@tanstack/react-query\";\nimport { QueryKeys } from \"@/modules/core\";\nimport { fetchCurationRecommendationsPage } from \"../requests\";\nimport { maskDmcaCurationPages } from \"../dmca\";\nimport type { CurationRecommendationsPage, CurationRecommendationsParams } from \"../types\";\nimport { dedupePagesBy } from \"./get-curation-feed-infinite-query-options\";\n\nexport const CURATION_RECOMMENDATIONS_PAGE_SIZE = 25;\n\n/**\n * Open posts with at least one active recommendation (route 4), ordered by\n * unique recommenders (networks) or by first recommendation time.\n */\nexport function getCurationRecommendationsInfiniteQueryOptions(\n params: CurationRecommendationsParams = {}\n) {\n const sort = params.sort ?? \"unique\";\n const limit = params.limit ?? CURATION_RECOMMENDATIONS_PAGE_SIZE;\n const normalized: Record<string, string> = { sort, limit: String(limit) };\n\n return infiniteQueryOptions({\n queryKey: QueryKeys.curation.recommendations(normalized),\n initialPageParam: undefined as string | undefined,\n queryFn: ({ pageParam, signal }) =>\n fetchCurationRecommendationsPage({ sort, limit }, pageParam, signal),\n getNextPageParam: (lastPage: CurationRecommendationsPage): string | undefined => {\n if (!lastPage || lastPage.items.length < limit) {\n return undefined;\n }\n const last = lastPage.items[lastPage.items.length - 1];\n return last?._cursor ?? lastPage.next_cursor ?? undefined;\n },\n // Route 4 items carry no post_id; the author/permlink pair is the identity.\n select: (data) =>\n maskDmcaCurationPages(dedupePagesBy(data, (item) => `${item.author}/${item.permlink}`)),\n staleTime: 10_000,\n });\n}\n\n"]}
1
+ {"version":3,"sources":["../../src/modules/curation/queries/get-curation-recommendations-infinite-query-options.ts"],"names":["CURATION_RECOMMENDATIONS_PAGE_SIZE","getCurationRecommendationsInfiniteQueryOptions","params","sort","limit","normalized","infiniteQueryOptions","QueryKeys","pageParam","signal","fetchCurationRecommendationsPage","lastPage","data","maskDmcaCurationPages","dedupePagesBy","item"],"mappings":"uNAOO,IAAMA,EAAqC,GAM3C,SAASC,EACdC,CAAAA,CAAwC,GACxC,CACA,IAAMC,EAAOD,CAAAA,CAAO,IAAA,EAAQ,SACtBE,CAAAA,CAAQF,CAAAA,CAAO,KAAA,EAASF,CAAAA,CACxBK,CAAAA,CAAqC,CAAE,KAAAF,CAAAA,CAAM,KAAA,CAAO,OAAOC,CAAK,CAAE,EAExE,OAAOE,oBAAAA,CAAqB,CAC1B,QAAA,CAAUC,CAAAA,CAAU,SAAS,eAAA,CAAgBF,CAAU,EACvD,gBAAA,CAAkB,MAAA,CAClB,QAAS,CAAC,CAAE,SAAA,CAAAG,CAAAA,CAAW,MAAA,CAAAC,CAAO,IAC5BC,CAAAA,CAAiC,CAAE,KAAAP,CAAAA,CAAM,KAAA,CAAAC,CAAM,CAAA,CAAGI,CAAAA,CAAWC,CAAM,CAAA,CACrE,gBAAA,CAAmBE,GACb,CAACA,CAAAA,EAAYA,EAAS,KAAA,CAAM,MAAA,CAASP,EACvC,MAAA,CAEWO,CAAAA,CAAS,KAAA,CAAMA,CAAAA,CAAS,KAAA,CAAM,MAAA,CAAS,CAAC,CAAA,EACxC,OAAA,EAAWA,EAAS,WAAA,EAAe,MAAA,CAGlD,OAASC,CAAAA,EACPC,GAAAA,CAAsBC,GAAAA,CAAcF,CAAAA,CAAOG,CAAAA,EAAS,CAAA,EAAGA,EAAK,MAAM,CAAA,CAAA,EAAIA,EAAK,QAAQ,CAAA,CAAE,CAAC,CAAA,CACxF,SAAA,CAAW,GACb,CAAC,CACH","file":"chunk-AZR63GSQ.js","sourcesContent":["import { infiniteQueryOptions } from \"@tanstack/react-query\";\nimport { QueryKeys } from \"@/modules/core\";\nimport { fetchCurationRecommendationsPage } from \"../requests\";\nimport { maskDmcaCurationPages } from \"../dmca\";\nimport type { CurationRecommendationsPage, CurationRecommendationsParams } from \"../types\";\nimport { dedupePagesBy } from \"./get-curation-feed-infinite-query-options\";\n\nexport const CURATION_RECOMMENDATIONS_PAGE_SIZE = 25;\n\n/**\n * Open posts with at least one active recommendation (route 4), ordered by\n * unique recommenders (networks) or by first recommendation time.\n */\nexport function getCurationRecommendationsInfiniteQueryOptions(\n params: CurationRecommendationsParams = {}\n) {\n const sort = params.sort ?? \"unique\";\n const limit = params.limit ?? CURATION_RECOMMENDATIONS_PAGE_SIZE;\n const normalized: Record<string, string> = { sort, limit: String(limit) };\n\n return infiniteQueryOptions({\n queryKey: QueryKeys.curation.recommendations(normalized),\n initialPageParam: undefined as string | undefined,\n queryFn: ({ pageParam, signal }) =>\n fetchCurationRecommendationsPage({ sort, limit }, pageParam, signal),\n getNextPageParam: (lastPage: CurationRecommendationsPage): string | undefined => {\n if (!lastPage || lastPage.items.length < limit) {\n return undefined;\n }\n const last = lastPage.items[lastPage.items.length - 1];\n return last?._cursor ?? lastPage.next_cursor ?? undefined;\n },\n // Route 4 items carry no post_id; the author/permlink pair is the identity.\n select: (data) =>\n maskDmcaCurationPages(dedupePagesBy(data, (item) => `${item.author}/${item.permlink}`)),\n staleTime: 10_000,\n });\n}\n\n"]}
@@ -1,2 +1,2 @@
1
- import {g}from'./chunk-4DTETBSG.js';import {a}from'./chunk-HEILHNSR.js';import {queryOptions}from'@tanstack/react-query';var m=/^[a-z0-9.-]{3,16}$/;function s(r){let e=m.test(r??"");return queryOptions({queryKey:a.curation.recommender(r),queryFn:({signal:n})=>{if(!e)throw new Error("[SDK][Curation] invalid recommender username");return g(r,n)},enabled:e,staleTime:6e4})}export{s as a};//# sourceMappingURL=chunk-VP72GHX2.js.map
2
- //# sourceMappingURL=chunk-VP72GHX2.js.map
1
+ import {g}from'./chunk-HBIRNFVS.js';import {a}from'./chunk-HEILHNSR.js';import {queryOptions}from'@tanstack/react-query';var m=/^[a-z0-9.-]{3,16}$/;function s(r){let e=m.test(r??"");return queryOptions({queryKey:a.curation.recommender(r),queryFn:({signal:n})=>{if(!e)throw new Error("[SDK][Curation] invalid recommender username");return g(r,n)},enabled:e,staleTime:6e4})}export{s as a};//# sourceMappingURL=chunk-E6UOGKIO.js.map
2
+ //# sourceMappingURL=chunk-E6UOGKIO.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/modules/curation/queries/get-curation-recommender-query-options.ts"],"names":["ACCOUNT_RE","getCurationRecommenderQueryOptions","username","valid","queryOptions","QueryKeys","signal","fetchCurationRecommenderStats"],"mappings":"yHAIA,IAAMA,CAAAA,CAAa,qBAWZ,SAASC,CAAAA,CAAmCC,CAAAA,CAAkB,CACnE,IAAMC,CAAAA,CAAQH,EAAW,IAAA,CAAKE,CAAAA,EAAY,EAAE,CAAA,CAE5C,OAAOE,YAAAA,CAAa,CAClB,QAAA,CAAUC,CAAAA,CAAU,QAAA,CAAS,WAAA,CAAYH,CAAQ,CAAA,CACjD,QAAS,CAAC,CAAE,MAAA,CAAAI,CAAO,CAAA,GAAM,CAGvB,GAAI,CAACH,CAAAA,CACH,MAAM,IAAI,KAAA,CAAM,8CAA8C,EAEhE,OAAOI,CAAAA,CAA8BL,CAAAA,CAAUI,CAAM,CACvD,CAAA,CACA,QAASH,CAAAA,CACT,SAAA,CAAW,GACb,CAAC,CACH","file":"chunk-VP72GHX2.js","sourcesContent":["import { queryOptions } from \"@tanstack/react-query\";\nimport { QueryKeys } from \"@/modules/core\";\nimport { fetchCurationRecommenderStats } from \"../requests\";\n\nconst ACCOUNT_RE = /^[a-z0-9.-]{3,16}$/;\n\n/**\n * One recommender's 90-day scorecard (route 14): how many recommendations they\n * made, how many were curated, dismissed or withdrawn, the resulting precision\n * and whether they count as trusted. Public and memoized 60 s at the gateway,\n * so a popover that opens twice costs one request.\n *\n * The route answers zeros with a neutral precision for a name it has never\n * seen, so a missing scorecard is data rather than an error.\n */\nexport function getCurationRecommenderQueryOptions(username: string) {\n const valid = ACCOUNT_RE.test(username ?? \"\");\n\n return queryOptions({\n queryKey: QueryKeys.curation.recommender(username),\n queryFn: ({ signal }) => {\n // Guarded twice: `enabled` gates automatic fetching only, a prefetch\n // still runs this.\n if (!valid) {\n throw new Error(\"[SDK][Curation] invalid recommender username\");\n }\n return fetchCurationRecommenderStats(username, signal);\n },\n enabled: valid,\n staleTime: 60_000,\n });\n}\n"]}
1
+ {"version":3,"sources":["../../src/modules/curation/queries/get-curation-recommender-query-options.ts"],"names":["ACCOUNT_RE","getCurationRecommenderQueryOptions","username","valid","queryOptions","QueryKeys","signal","fetchCurationRecommenderStats"],"mappings":"yHAIA,IAAMA,CAAAA,CAAa,qBAWZ,SAASC,CAAAA,CAAmCC,CAAAA,CAAkB,CACnE,IAAMC,CAAAA,CAAQH,EAAW,IAAA,CAAKE,CAAAA,EAAY,EAAE,CAAA,CAE5C,OAAOE,YAAAA,CAAa,CAClB,QAAA,CAAUC,CAAAA,CAAU,QAAA,CAAS,WAAA,CAAYH,CAAQ,CAAA,CACjD,QAAS,CAAC,CAAE,MAAA,CAAAI,CAAO,CAAA,GAAM,CAGvB,GAAI,CAACH,CAAAA,CACH,MAAM,IAAI,KAAA,CAAM,8CAA8C,EAEhE,OAAOI,CAAAA,CAA8BL,CAAAA,CAAUI,CAAM,CACvD,CAAA,CACA,QAASH,CAAAA,CACT,SAAA,CAAW,GACb,CAAC,CACH","file":"chunk-E6UOGKIO.js","sourcesContent":["import { queryOptions } from \"@tanstack/react-query\";\nimport { QueryKeys } from \"@/modules/core\";\nimport { fetchCurationRecommenderStats } from \"../requests\";\n\nconst ACCOUNT_RE = /^[a-z0-9.-]{3,16}$/;\n\n/**\n * One recommender's 90-day scorecard (route 14): how many recommendations they\n * made, how many were curated, dismissed or withdrawn, the resulting precision\n * and whether they count as trusted. Public and memoized 60 s at the gateway,\n * so a popover that opens twice costs one request.\n *\n * The route answers zeros with a neutral precision for a name it has never\n * seen, so a missing scorecard is data rather than an error.\n */\nexport function getCurationRecommenderQueryOptions(username: string) {\n const valid = ACCOUNT_RE.test(username ?? \"\");\n\n return queryOptions({\n queryKey: QueryKeys.curation.recommender(username),\n queryFn: ({ signal }) => {\n // Guarded twice: `enabled` gates automatic fetching only, a prefetch\n // still runs this.\n if (!valid) {\n throw new Error(\"[SDK][Curation] invalid recommender username\");\n }\n return fetchCurationRecommenderStats(username, signal);\n },\n enabled: valid,\n staleTime: 60_000,\n });\n}\n"]}
@@ -1,2 +1,2 @@
1
- import {o}from'./chunk-4DTETBSG.js';import {a}from'./chunk-HEILHNSR.js';import {queryOptions}from'@tanstack/react-query';function c(i,n){return queryOptions({queryKey:a.curation.application(i),queryFn:({signal:e})=>{if(!i||!n)throw new Error("[SDK][Curation] reading the own application needs a signed-in account");return o(n,e)},enabled:!!i&&!!n,staleTime:6e4})}export{c as a};//# sourceMappingURL=chunk-UPLGU6G7.js.map
2
- //# sourceMappingURL=chunk-UPLGU6G7.js.map
1
+ import {o}from'./chunk-HBIRNFVS.js';import {a}from'./chunk-HEILHNSR.js';import {queryOptions}from'@tanstack/react-query';function c(i,n){return queryOptions({queryKey:a.curation.application(i),queryFn:({signal:e})=>{if(!i||!n)throw new Error("[SDK][Curation] reading the own application needs a signed-in account");return o(n,e)},enabled:!!i&&!!n,staleTime:6e4})}export{c as a};//# sourceMappingURL=chunk-F6NBFXMD.js.map
2
+ //# sourceMappingURL=chunk-F6NBFXMD.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/modules/curation/queries/get-curation-application-query-options.ts"],"names":["getCurationApplicationQueryOptions","username","code","queryOptions","QueryKeys","signal","curationApplicationMineRequest"],"mappings":"yHASO,SAASA,EACdC,CAAAA,CACAC,CAAAA,CACA,CACA,OAAOC,YAAAA,CAAa,CAClB,SAAUC,CAAAA,CAAU,QAAA,CAAS,WAAA,CAAYH,CAAQ,CAAA,CACjD,OAAA,CAAS,CAAC,CAAE,MAAA,CAAAI,CAAO,CAAA,GAAM,CAGvB,GAAI,CAACJ,CAAAA,EAAY,CAACC,EAChB,MAAM,IAAI,MACR,uEACF,CAAA,CAEF,OAAOI,CAAAA,CAA+BJ,CAAAA,CAAMG,CAAM,CACpD,CAAA,CACA,OAAA,CAAS,CAAC,CAACJ,CAAAA,EAAY,CAAC,CAACC,CAAAA,CACzB,SAAA,CAAW,GACb,CAAC,CACH","file":"chunk-UPLGU6G7.js","sourcesContent":["import { queryOptions } from \"@tanstack/react-query\";\nimport { QueryKeys } from \"@/modules/core\";\nimport { curationApplicationMineRequest } from \"../requests\";\n\n/**\n * The viewer's own guest curator application, the window it was made in and\n * whether they are already on the roster. Keyed by the viewer: it is private,\n * and the answer is different for every account.\n */\nexport function getCurationApplicationQueryOptions(\n username: string | undefined,\n code: string | undefined,\n) {\n return queryOptions({\n queryKey: QueryKeys.curation.application(username),\n queryFn: ({ signal }) => {\n // Guarded twice: `enabled` gates automatic fetching only, a prefetch or a\n // fetchQuery still runs this, and the request would throw \"missing auth\".\n if (!username || !code) {\n throw new Error(\n \"[SDK][Curation] reading the own application needs a signed-in account\",\n );\n }\n return curationApplicationMineRequest(code, signal);\n },\n enabled: !!username && !!code,\n staleTime: 60_000,\n });\n}\n"]}
1
+ {"version":3,"sources":["../../src/modules/curation/queries/get-curation-application-query-options.ts"],"names":["getCurationApplicationQueryOptions","username","code","queryOptions","QueryKeys","signal","curationApplicationMineRequest"],"mappings":"yHASO,SAASA,EACdC,CAAAA,CACAC,CAAAA,CACA,CACA,OAAOC,YAAAA,CAAa,CAClB,SAAUC,CAAAA,CAAU,QAAA,CAAS,WAAA,CAAYH,CAAQ,CAAA,CACjD,OAAA,CAAS,CAAC,CAAE,MAAA,CAAAI,CAAO,CAAA,GAAM,CAGvB,GAAI,CAACJ,CAAAA,EAAY,CAACC,EAChB,MAAM,IAAI,MACR,uEACF,CAAA,CAEF,OAAOI,CAAAA,CAA+BJ,CAAAA,CAAMG,CAAM,CACpD,CAAA,CACA,OAAA,CAAS,CAAC,CAACJ,CAAAA,EAAY,CAAC,CAACC,CAAAA,CACzB,SAAA,CAAW,GACb,CAAC,CACH","file":"chunk-F6NBFXMD.js","sourcesContent":["import { queryOptions } from \"@tanstack/react-query\";\nimport { QueryKeys } from \"@/modules/core\";\nimport { curationApplicationMineRequest } from \"../requests\";\n\n/**\n * The viewer's own guest curator application, the window it was made in and\n * whether they are already on the roster. Keyed by the viewer: it is private,\n * and the answer is different for every account.\n */\nexport function getCurationApplicationQueryOptions(\n username: string | undefined,\n code: string | undefined,\n) {\n return queryOptions({\n queryKey: QueryKeys.curation.application(username),\n queryFn: ({ signal }) => {\n // Guarded twice: `enabled` gates automatic fetching only, a prefetch or a\n // fetchQuery still runs this, and the request would throw \"missing auth\".\n if (!username || !code) {\n throw new Error(\n \"[SDK][Curation] reading the own application needs a signed-in account\",\n );\n }\n return curationApplicationMineRequest(code, signal);\n },\n enabled: !!username && !!code,\n staleTime: 60_000,\n });\n}\n"]}
@@ -0,0 +1,2 @@
1
+ import {a as a$1}from'./chunk-SEACJS36.js';import {c as c$1}from'./chunk-Q567KEFE.js';import {b as b$1}from'./chunk-OS3FCYZY.js';var P="/private-api/curation-desk",d=class extends Error{constructor(e,o,r){super(e);b$1(this,"status");b$1(this,"data");this.name="CurationApiError",this.status=o,this.data=r;}};function c(t){return typeof t=="object"&&t!==null&&!Array.isArray(t)}var f=t=>c(t)&&Array.isArray(t.items),w=t=>c(t)&&Array.isArray(t.curators),b=t=>c(t)&&Array.isArray(t.recommenders),x=t=>c(t)&&"vp"in t,_=["window_days","recommended","curated","dismissed","withdrawn","precision"],M=t=>c(t)&&_.every(n=>typeof t[n]=="number")&&typeof t.trusted=="boolean";async function k(t,n,e){if(!t.ok){let i;try{i=await t.json();}catch{i=void 0;}throw new d(`Failed to ${n}: ${t.status}`,t.status,i)}let o=t.headers?.get?.("content-type")??"";if(o&&!o.includes("json"))throw new d(`Unexpected response for ${n}`,t.status);let r;try{r=await t.json();}catch{throw new d(`Unexpected response for ${n}`,t.status)}if(e&&!e(r))throw new d(`Unexpected response for ${n}`,t.status);return r}var E=/^hive-\d{5,6}$/,T=/^[a-z0-9]{8,16}$/,v=new Set(["hide_curated","hide_reviewed","hide_snoozed"]),y=["sort","seed","view","app","community","window","rep_min","rep_max","min_words","max_words","has_images","new_authors","recommended","flagged","hide_curated","hide_reviewed","hide_snoozed","limit"];function A(t={}){let n=t,e={};for(let o of y){let r=n[o];if(r==null||r==="")continue;if(typeof r=="boolean"){v.has(o)?r||(e[o]="0"):r&&(e[o]="1");continue}if(typeof r=="number"){if(!Number.isFinite(r))continue;e[o]=String(Math.trunc(r));continue}let i=String(r);(o==="app"||o==="window")&&i==="all"||o==="community"&&!E.test(i)||o==="seed"&&!T.test(i)||(e[o]=i);}return e.sort!=="random"&&delete e.seed,e}function D(t,n){let e=new URLSearchParams;for(let r of y)t[r]!==void 0&&e.set(r,t[r]);n&&e.set("cursor",n);let o=e.toString();return o?`?${o}`:""}function S(t){return `${c$1.privateApiHost}${P}${t}`}var q=new Set(["localhost","127.0.0.1","::1","[::1]"]);function I(t){let n=c$1.privateApiHost||"",e=typeof window<"u"?window.location?.href:void 0,o;try{o=e?new URL(n,e):new URL(n);}catch{return}if(o.protocol!=="https:"&&!(o.protocol==="http:"&&q.has(o.hostname)))throw new d(`Refusing to ${t} over an insecure connection`,0)}async function p(t,n,e,o){let i=await a$1()(S(t),{method:"GET",signal:e});return k(i,n,o)}async function a(t,n,e,o,r,i){if(!n)throw new Error("[SDK][Curation] missing auth");I(o);let u=await a$1()(S(t),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({...e,code:n}),redirect:"error",signal:r});return k(u,o,i)}function K(t,n,e){return p(`/feed${D(A(t),n)}`,"fetch curation feed",e,f)}function O(t){return p("/status","fetch curation status",t,x)}function N(t){return p("/roster","fetch curation roster",t,w)}function z(t,n,e){let o=new URLSearchParams;t.sort&&o.set("sort",t.sort),t.limit&&o.set("limit",String(t.limit)),n&&o.set("cursor",n);let r=o.toString();return p(`/recommendations${r?`?${r}`:""}`,"fetch curation recommendations",e,f)}function j(t,n){return p(`/recommender/${encodeURIComponent(t)}`,"fetch recommender stats",n,M)}function W(t,n,e){return p(`/post/${encodeURIComponent(t)}/${encodeURIComponent(n)}`,"fetch curation post",e,b)}function V(t,n,e,o){let r={...A(n)};return e&&(r.cursor=e),a("/roster-feed",t,r,"fetch roster feed",o,f)}function H(t,n,e){return a("/tick",t,{since:n.since,need:n.need.slice(0,100),visible:n.visible.slice(0,100)},"tick",e)}function J(t,n){return a("/roster-list",t,{},"list roster",n,w)}function B(t,n){let{curator:e,role:o,rules:r,note:i,term_days:s}=n;if(!e||!o)throw new Error("[SDK][Curation] roster set needs a curator and a role");let u={curator:e,role:o};return r&&(u.rules=r),i!==void 0&&(u.note=i),s!==void 0&&(u.term_days=s),a("/roster-set",t,u,"set curator")}function G(t,n){if(!n)throw new Error("[SDK][Curation] roster retire needs a curator");return a("/roster-retire",t,{curator:n},"retire curator")}var l=t=>c(t)&&"application"in t,F=t=>c(t)&&Array.isArray(t.applications),$=t=>c(t)&&c(t.window);function Q(t,n){let e=n.motivation?.trim(),o=n.availability?.trim(),r=n.pick?.trim();if(!e||!o||!r)throw new Error("[SDK][Curation] an application needs all three answers");return a("/application-apply",t,{motivation:e,availability:o,pick:r},"apply",void 0,l)}function X(t,n){return a("/application-mine",t,{},"read your application",n,l)}function Y(t){return a("/application-withdraw",t,{},"withdraw your application",void 0,l)}function Z(t,n={},e){let o={};return n.state&&(o.state=n.state),n.limit&&(o.limit=n.limit),a("/application-list",t,o,"list applications",e,F)}function tt(t,n){let{applicant:e,state:o,role:r,note:i}=n;if(!e||!o)throw new Error("[SDK][Curation] a decision needs an applicant and a state");let s={applicant:e,state:o};return o==="accepted"&&r&&(s.role=r),i!==void 0&&(s.note=i),a("/application-decide",t,s,"decide an application",void 0,l)}function nt(t,n){let{applicant:e,vote:o,note:r}=n;if(!e||!o)throw new Error("[SDK][Curation] a vote needs an applicant and a value");let i={applicant:e,vote:o};return r!==void 0&&(i.note=r),a("/application-vote",t,i,"vote on an application",void 0,l)}function et(t,n){let e={};if(n.open!==void 0&&(e.open=n.open),n.message!==void 0&&(e.message=n.message),n.quorum!==void 0&&(e.quorum=n.quorum),n.term_days!==void 0&&(e.term_days=n.term_days),Object.keys(e).length===0)throw new Error("[SDK][Curation] a window save needs something to set");return a("/application-window",t,e,"set the application window",void 0,$)}function ot(t,n){let{author:e,permlink:o,state:r,reason:i,note:s,snooze_until:u,lane:g}=n;if(!e||!o||!r)throw new Error("[SDK][Curation] mark needs author, permlink and state");let m={author:e,permlink:o,state:r};return i&&(m.reason=i),s&&(m.note=s),u&&(m.snooze_until=u),g&&(m.lane=g),a("/mark",t,m,"set mark")}function rt(t,n){if(!n.author||!n.permlink)throw new Error("[SDK][Curation] mark-clear needs author and permlink");return a("/mark-clear",t,{author:n.author,permlink:n.permlink},"clear mark")}function it(t,n={},e){let o={};return n.state&&(o.state=n.state),n.cursor&&(o.cursor=n.cursor),n.limit&&(o.limit=n.limit),a("/marks",t,o,"fetch my marks",e,f)}function at(t,n){if(!Number.isFinite(n.post_id)||!n.action)throw new Error("[SDK][Curation] cursor needs post_id and action");let e={post_id:n.post_id,action:n.action};return n.reason&&(e.reason=n.reason),a("/cursor",t,e,"move cursor")}var U=/^[0-9a-f]{40}$/;function st(t,n){let{author:e,permlink:o,trx_id:r,ua_class:i}=n;if(!e||!o||!i)throw new Error("[SDK][Curation] recommend-meta needs author, permlink and ua_class");let s={author:e,permlink:o,ua_class:i};return typeof r=="string"&&U.test(r)&&(s.trx_id=r),a("/recommend-meta",t,s,"send recommendation meta")}function ut(t,n){if(!n.author||!n.permlink||!n.action)throw new Error("[SDK][Curation] recommendation-dismiss needs author, permlink and action");return a("/recommendation-dismiss",t,{author:n.author,permlink:n.permlink,action:n.action},"dismiss recommendation")}export{d as a,A as b,K as c,O as d,N as e,z as f,j as g,W as h,V as i,H as j,J as k,B as l,G as m,Q as n,X as o,Y as p,Z as q,tt as r,nt as s,et as t,ot as u,rt as v,it as w,at as x,st as y,ut as z};//# sourceMappingURL=chunk-HBIRNFVS.js.map
2
+ //# sourceMappingURL=chunk-HBIRNFVS.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/modules/curation/requests.ts"],"names":["ROUTE","CurationApiError","message","status","data","__publicField","isRecord","hasItems","hasCurators","hasRecommenders","isStatus","SCORECARD_COUNTS","isRecommenderStats","key","parse","response","what","check","contentType","COMMUNITY_RE","SEED_RE","DEFAULT_TRUE","PARAM_ORDER","normalizeCurationParams","params","source","out","name","value","text","toQuery","normalized","cursor","search","url","path","CONFIG","LOOPBACK_HOSTS","assertCredentialTransport","host","page","parsed","getJson","signal","getBoundFetch","postJson","code","body","fetchCurationFeedPage","fetchCurationStatus","fetchCurationRoster","fetchCurationRecommendationsPage","fetchCurationRecommenderStats","username","fetchCurationPost","author","permlink","curationRosterFeedRequest","curationTickRequest","curationRosterListRequest","curationRosterSetRequest","input","curator","role","rules","note","term_days","curationRosterRetireRequest","hasApplication","hasApplications","hasWindow","curationApplicationApplyRequest","answers","motivation","availability","pick","curationApplicationMineRequest","curationApplicationWithdrawRequest","curationApplicationListRequest","curationApplicationDecideRequest","applicant","state","curationApplicationVoteRequest","vote","curationApplicationWindowRequest","curationMarkRequest","reason","snooze_until","lane","curationMarkClearRequest","curationMyMarksRequest","curationCursorRequest","TRX_ID_RE","curationRecommendMetaRequest","trx_id","ua_class","curationDismissRecoRequest"],"mappings":"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","file":"chunk-HBIRNFVS.js","sourcesContent":["import { CONFIG, getBoundFetch } from \"@/modules/core\";\nimport type {\n CurationApplication,\n CurationApplicationDecideInput,\n CurationApplicationVoteInput,\n CurationApplicationVoteResult,\n CurationApplicationList,\n CurationApplicationMine,\n CurationApplicationState,\n CurationApplicationWindow,\n CurationCursorInput,\n CurationCursorResponse,\n CurationDismissRecoInput,\n CurationDismissRecoResponse,\n CurationFeedPage,\n CurationFeedParams,\n CurationMarkClearResponse,\n CurationMarkInput,\n CurationMarkResponse,\n CurationMyMarksParams,\n CurationMyMarksResponse,\n CurationPost,\n CurationRecommendMetaInput,\n CurationRecommendationsPage,\n CurationRecommendationsParams,\n CurationRecommenderStats,\n CurationRoster,\n CurationRosterAdminEntry,\n CurationRosterAdminList,\n CurationRosterFeedPage,\n CurationRosterFeedParams,\n CurationRosterSetInput,\n CurationStatus,\n CurationTickRequest,\n CurationTickResponse,\n} from \"./types\";\n\n/**\n * Curation desk transport. Public GETs carry no identity; authed POSTs take the\n * HiveSigner access `code` as an explicit argument and send it in the body.\n * Token freshness is the caller's job (web: ensureValidToken; mobile: its token\n * wrapper), so a builder never captures a code that can expire.\n */\n\nconst ROUTE = \"/private-api/curation-desk\";\n\nexport class CurationApiError extends Error {\n readonly status: number;\n readonly data: unknown;\n\n constructor(message: string, status: number, data?: unknown) {\n super(message);\n this.name = \"CurationApiError\";\n this.status = status;\n this.data = data;\n }\n}\n\n/**\n * A light shape check per response family, not a schema validator: it answers\n * \"is this the kind of body the consumers dereference\", so a 200 that carries\n * something else (an error envelope, another route's body) fails here instead\n * of inside a query builder reading `.items.length`.\n */\ntype ShapeCheck = (data: unknown) => boolean;\n\nfunction isRecord(data: unknown): data is Record<string, unknown> {\n return typeof data === \"object\" && data !== null && !Array.isArray(data);\n}\n\n/** Every paged family: the list is what the consumers page over. */\nconst hasItems: ShapeCheck = (data) => isRecord(data) && Array.isArray(data.items);\nconst hasCurators: ShapeCheck = (data) => isRecord(data) && Array.isArray(data.curators);\n/** Route 5: the viewer finds their own recommendation by name in this list. */\nconst hasRecommenders: ShapeCheck = (data) => isRecord(data) && Array.isArray(data.recommenders);\n/** `vp` is nullable, so the field has to be present rather than truthy. */\nconst isStatus: ShapeCheck = (data) => isRecord(data) && \"vp\" in data;\n/**\n * A scorecard is counted, never absent: an unknown recommender answers zeros\n * rather than a 404, so a body without a numeric `recommended` is another\n * route's answer and not an empty scorecard.\n */\n/** Every number the scorecard prints, the window it prints them for included. */\nconst SCORECARD_COUNTS = [\"window_days\", \"recommended\", \"curated\", \"dismissed\", \"withdrawn\", \"precision\"] as const;\nconst isRecommenderStats: ShapeCheck = (data) =>\n isRecord(data) &&\n SCORECARD_COUNTS.every((key) => typeof data[key] === \"number\") &&\n typeof data.trusted === \"boolean\";\n\nasync function parse<T>(response: Response, what: string, check?: ShapeCheck): Promise<T> {\n if (!response.ok) {\n let data: unknown = undefined;\n try {\n data = await response.json();\n } catch {\n data = undefined;\n }\n throw new CurationApiError(`Failed to ${what}: ${response.status}`, response.status, data);\n }\n // The gateway answers an unknown GET with a 200 HTML page. That is never an\n // empty queue, so a non-JSON body is an error too. A body that only claims\n // to be JSON gets the same treatment: parsing it must not reach the caller\n // as a SyntaxError with no status on it.\n const contentType = response.headers?.get?.(\"content-type\") ?? \"\";\n if (contentType && !contentType.includes(\"json\")) {\n throw new CurationApiError(`Unexpected response for ${what}`, response.status);\n }\n let data: unknown;\n try {\n data = await response.json();\n } catch {\n throw new CurationApiError(`Unexpected response for ${what}`, response.status);\n }\n if (check && !check(data)) {\n throw new CurationApiError(`Unexpected response for ${what}`, response.status);\n }\n return data as T;\n}\n\nconst COMMUNITY_RE = /^hive-\\d{5,6}$/;\nconst SEED_RE = /^[a-z0-9]{8,16}$/;\n\n/**\n * Booleans the desk already defaults to true, so only an explicit false says\n * anything. Sending the \"1\" would split memo and cache keys against a gateway\n * that drops it.\n */\nconst DEFAULT_TRUE = new Set([\"hide_curated\", \"hide_reviewed\", \"hide_snoozed\"]);\n\n/** Fixed emission order: keeps memo and shared-cache keys stable across clients. */\nconst PARAM_ORDER = [\n \"sort\",\n \"seed\",\n \"view\",\n \"app\",\n \"community\",\n \"window\",\n \"rep_min\",\n \"rep_max\",\n \"min_words\",\n \"max_words\",\n \"has_images\",\n \"new_authors\",\n \"recommended\",\n \"flagged\",\n \"hide_curated\",\n \"hide_reviewed\",\n \"hide_snoozed\",\n \"limit\",\n] as const;\n\nexport type NormalizedCurationParams = Record<string, string>;\n\n/**\n * Drops defaults and unknown values, emits fixed-order string params. Used for\n * the query string, the roster body and the React Query key, so all three agree.\n */\nexport function normalizeCurationParams(\n params: CurationRosterFeedParams | CurationFeedParams = {}\n): NormalizedCurationParams {\n const source = params as Record<string, unknown>;\n const out: NormalizedCurationParams = {};\n for (const name of PARAM_ORDER) {\n const value = source[name];\n if (value === undefined || value === null || value === \"\") continue;\n if (typeof value === \"boolean\") {\n if (DEFAULT_TRUE.has(name)) {\n if (!value) out[name] = \"0\";\n } else if (value) {\n out[name] = \"1\";\n }\n continue;\n }\n if (typeof value === \"number\") {\n if (!Number.isFinite(value)) continue;\n out[name] = String(Math.trunc(value));\n continue;\n }\n const text = String(value);\n if ((name === \"app\" || name === \"window\") && text === \"all\") continue;\n if (name === \"community\" && !COMMUNITY_RE.test(text)) continue;\n if (name === \"seed\" && !SEED_RE.test(text)) continue;\n out[name] = text;\n }\n // The seed only means something for the random order.\n if (out.sort !== \"random\") delete out.seed;\n return out;\n}\n\nfunction toQuery(normalized: NormalizedCurationParams, cursor?: string): string {\n const search = new URLSearchParams();\n for (const name of PARAM_ORDER) {\n if (normalized[name] !== undefined) search.set(name, normalized[name]);\n }\n if (cursor) search.set(\"cursor\", cursor);\n const text = search.toString();\n return text ? `?${text}` : \"\";\n}\n\nfunction url(path: string): string {\n return `${CONFIG.privateApiHost}${ROUTE}${path}`;\n}\n\n/** Hosts a credential may reach without TLS: a local gateway has no certificate. */\nconst LOOPBACK_HOSTS = new Set([\"localhost\", \"127.0.0.1\", \"::1\", \"[::1]\"]);\n\n/**\n * The authed routes put the HiveSigner code in the body, so the transport is\n * the only thing keeping a replayable credential private. A relative host\n * (empty for same-origin, `//gateway`, `/api`) takes the page's own transport,\n * so it is resolved against the page before the scheme is read.\n */\nfunction assertCredentialTransport(what: string) {\n const host = CONFIG.privateApiHost || \"\";\n const page = typeof window !== \"undefined\" ? window.location?.href : undefined;\n let parsed: URL;\n try {\n parsed = page ? new URL(host, page) : new URL(host);\n } catch {\n // Relative with no page to resolve against: outside a browser nothing can\n // be fetched from a relative URL either.\n return;\n }\n if (parsed.protocol === \"https:\") return;\n if (parsed.protocol === \"http:\" && LOOPBACK_HOSTS.has(parsed.hostname)) return;\n throw new CurationApiError(`Refusing to ${what} over an insecure connection`, 0);\n}\n\nasync function getJson<T>(\n path: string,\n what: string,\n signal?: AbortSignal,\n check?: ShapeCheck\n): Promise<T> {\n const fetchApi = getBoundFetch();\n const response = await fetchApi(url(path), { method: \"GET\", signal });\n return parse<T>(response, what, check);\n}\n\nasync function postJson<T>(\n path: string,\n code: string | undefined,\n body: Record<string, unknown>,\n what: string,\n signal?: AbortSignal,\n check?: ShapeCheck\n): Promise<T> {\n if (!code) {\n throw new Error(\"[SDK][Curation] missing auth\");\n }\n assertCredentialTransport(what);\n const fetchApi = getBoundFetch();\n const response = await fetchApi(url(path), {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ ...body, code }),\n // A 307 or 308 would resend this body, code included, to wherever the\n // redirect points.\n redirect: \"error\",\n signal,\n });\n return parse<T>(response, what, check);\n}\n\n// ---------------------------------------------------------------------------\n// Public reads (used by the query builders)\n// ---------------------------------------------------------------------------\n\nexport function fetchCurationFeedPage(\n params: CurationFeedParams,\n cursor?: string,\n signal?: AbortSignal\n): Promise<CurationFeedPage> {\n return getJson<CurationFeedPage>(\n `/feed${toQuery(normalizeCurationParams(params), cursor)}`,\n \"fetch curation feed\",\n signal,\n hasItems\n );\n}\n\nexport function fetchCurationStatus(signal?: AbortSignal): Promise<CurationStatus> {\n return getJson<CurationStatus>(\"/status\", \"fetch curation status\", signal, isStatus);\n}\n\nexport function fetchCurationRoster(signal?: AbortSignal): Promise<CurationRoster> {\n return getJson<CurationRoster>(\"/roster\", \"fetch curation roster\", signal, hasCurators);\n}\n\nexport function fetchCurationRecommendationsPage(\n params: CurationRecommendationsParams,\n cursor?: string,\n signal?: AbortSignal\n): Promise<CurationRecommendationsPage> {\n const search = new URLSearchParams();\n if (params.sort) search.set(\"sort\", params.sort);\n if (params.limit) search.set(\"limit\", String(params.limit));\n if (cursor) search.set(\"cursor\", cursor);\n const text = search.toString();\n return getJson<CurationRecommendationsPage>(\n `/recommendations${text ? `?${text}` : \"\"}`,\n \"fetch curation recommendations\",\n signal,\n hasItems\n );\n}\n\nexport function fetchCurationRecommenderStats(\n username: string,\n signal?: AbortSignal\n): Promise<CurationRecommenderStats> {\n return getJson<CurationRecommenderStats>(\n `/recommender/${encodeURIComponent(username)}`,\n \"fetch recommender stats\",\n signal,\n isRecommenderStats\n );\n}\n\nexport function fetchCurationPost(\n author: string,\n permlink: string,\n signal?: AbortSignal\n): Promise<CurationPost> {\n return getJson<CurationPost>(\n `/post/${encodeURIComponent(author)}/${encodeURIComponent(permlink)}`,\n \"fetch curation post\",\n signal,\n hasRecommenders\n );\n}\n\n// ---------------------------------------------------------------------------\n// Authed writes and reads (code in the body)\n// ---------------------------------------------------------------------------\n\nexport function curationRosterFeedRequest(\n code: string | undefined,\n params: CurationRosterFeedParams,\n cursor?: string,\n signal?: AbortSignal\n): Promise<CurationRosterFeedPage> {\n const body: Record<string, unknown> = { ...normalizeCurationParams(params) };\n if (cursor) body.cursor = cursor;\n return postJson<CurationRosterFeedPage>(\n \"/roster-feed\",\n code,\n body,\n \"fetch roster feed\",\n signal,\n hasItems\n );\n}\n\nexport function curationTickRequest(\n code: string | undefined,\n body: CurationTickRequest,\n signal?: AbortSignal\n): Promise<CurationTickResponse> {\n return postJson<CurationTickResponse>(\n \"/tick\",\n code,\n {\n since: body.since,\n need: body.need.slice(0, 100),\n visible: body.visible.slice(0, 100),\n },\n \"tick\",\n signal\n );\n}\n\n/**\n * The roster admin routes. All three are admin-only upstream, and all three are\n * POSTs: the private view carries notes and retired rows, which must never enter\n * the edge-cached roster GET.\n */\nexport function curationRosterListRequest(\n code: string | undefined,\n signal?: AbortSignal\n): Promise<CurationRosterAdminList> {\n // Same shape check as the public roster: a 200 carrying an error envelope, or any\n // body without `curators`, must reach the query's error path. Without it the panel\n // renders `data?.curators ?? []` and an outage looks like an empty roster.\n return postJson<CurationRosterAdminList>(\"/roster-list\", code, {}, \"list roster\", signal, hasCurators);\n}\n\nexport function curationRosterSetRequest(\n code: string | undefined,\n input: CurationRosterSetInput\n): Promise<{ curator: CurationRosterAdminEntry }> {\n const { curator, role, rules, note, term_days } = input;\n if (!curator || !role) {\n throw new Error(\"[SDK][Curation] roster set needs a curator and a role\");\n }\n const body: Record<string, unknown> = { curator, role };\n // Sent whole or not at all: the backend replaces the stored rules with what\n // arrives, so a partial object would silently drop the rules left out.\n if (rules) body.rules = rules;\n if (note !== undefined) body.note = note;\n // `!== undefined`, never a truthiness test: 0 is the one value that MEANS\n // something here, and it is the whole of \"keep this seat\".\n if (term_days !== undefined) body.term_days = term_days;\n return postJson<{ curator: CurationRosterAdminEntry }>(\"/roster-set\", code, body, \"set curator\");\n}\n\nexport function curationRosterRetireRequest(\n code: string | undefined,\n curator: string\n): Promise<{ ok: boolean; curator: string }> {\n if (!curator) {\n throw new Error(\"[SDK][Curation] roster retire needs a curator\");\n }\n return postJson<{ ok: boolean; curator: string }>(\n \"/roster-retire\",\n code,\n { curator },\n \"retire curator\"\n );\n}\n\n/**\n * Guest curator applications. Apply, mine and withdraw are open to any signed-in\n * account; the other three are admin-only upstream. All six are POSTs, so every\n * private field stays off the edge-cached GET tier.\n */\nconst hasApplication: ShapeCheck = (data) => isRecord(data) && \"application\" in data;\nconst hasApplications: ShapeCheck = (data) => isRecord(data) && Array.isArray(data.applications);\nconst hasWindow: ShapeCheck = (data) => isRecord(data) && isRecord(data.window);\n\nexport function curationApplicationApplyRequest(\n code: string | undefined,\n answers: { motivation: string; availability: string; pick: string }\n): Promise<{ application: CurationApplication; window: CurationApplicationWindow }> {\n const motivation = answers.motivation?.trim();\n const availability = answers.availability?.trim();\n const pick = answers.pick?.trim();\n if (!motivation || !availability || !pick) {\n throw new Error(\"[SDK][Curation] an application needs all three answers\");\n }\n return postJson(\"/application-apply\", code, { motivation, availability, pick }, \"apply\", undefined, hasApplication);\n}\n\nexport function curationApplicationMineRequest(\n code: string | undefined,\n signal?: AbortSignal\n): Promise<CurationApplicationMine> {\n return postJson(\"/application-mine\", code, {}, \"read your application\", signal, hasApplication);\n}\n\nexport function curationApplicationWithdrawRequest(\n code: string | undefined\n): Promise<{ application: CurationApplication }> {\n return postJson(\"/application-withdraw\", code, {}, \"withdraw your application\", undefined, hasApplication);\n}\n\nexport function curationApplicationListRequest(\n code: string | undefined,\n params: { state?: CurationApplicationState; limit?: number } = {},\n signal?: AbortSignal\n): Promise<CurationApplicationList> {\n const body: Record<string, unknown> = {};\n if (params.state) body.state = params.state;\n if (params.limit) body.limit = params.limit;\n // Same reason the roster list checks its shape: without it a 200 carrying an\n // error envelope renders as an empty queue rather than reaching the error path.\n return postJson(\"/application-list\", code, body, \"list applications\", signal, hasApplications);\n}\n\nexport function curationApplicationDecideRequest(\n code: string | undefined,\n input: CurationApplicationDecideInput\n): Promise<{ application: CurationApplication }> {\n const { applicant, state, role, note } = input;\n if (!applicant || !state) {\n throw new Error(\"[SDK][Curation] a decision needs an applicant and a state\");\n }\n const body: Record<string, unknown> = { applicant, state };\n // The role belongs to an acceptance only. The desk ignores it on a decline\n // rather than refusing it, so sending one would be a lie in the audit log.\n if (state === \"accepted\" && role) body.role = role;\n if (note !== undefined) body.note = note;\n return postJson(\"/application-decide\", code, body, \"decide an application\", undefined, hasApplication);\n}\n\nexport function curationApplicationVoteRequest(\n code: string | undefined,\n input: CurationApplicationVoteInput\n): Promise<CurationApplicationVoteResult> {\n const { applicant, vote, note } = input;\n if (!applicant || !vote) {\n throw new Error(\"[SDK][Curation] a vote needs an applicant and a value\");\n }\n const body: Record<string, unknown> = { applicant, vote };\n if (note !== undefined) body.note = note;\n return postJson(\"/application-vote\", code, body, \"vote on an application\", undefined, hasApplication);\n}\n\nexport function curationApplicationWindowRequest(\n code: string | undefined,\n input: { open?: boolean; message?: string | null; quorum?: number; term_days?: number }\n): Promise<{ window: CurationApplicationWindow; quorum: number; term_days: number }> {\n const body: Record<string, unknown> = {};\n // Every field is sent only when it is being CHANGED. Upstream reads an absent field as\n // \"leave it\", and one settings row holds all four: a save that carried the others would\n // put whatever this caller last read back over whatever changed since. `open` matters\n // most, because a stale one reopens applications to readers who act on it.\n if (input.open !== undefined) body.open = input.open;\n // A present null clears the message; absent leaves the stored one in place.\n if (input.message !== undefined) body.message = input.message;\n if (input.quorum !== undefined) body.quorum = input.quorum;\n if (input.term_days !== undefined) body.term_days = input.term_days;\n if (Object.keys(body).length === 0) {\n throw new Error(\"[SDK][Curation] a window save needs something to set\");\n }\n return postJson(\"/application-window\", code, body, \"set the application window\", undefined, hasWindow);\n}\n\nexport function curationMarkRequest(\n code: string | undefined,\n input: CurationMarkInput\n): Promise<CurationMarkResponse> {\n const { author, permlink, state, reason, note, snooze_until, lane } = input;\n if (!author || !permlink || !state) {\n throw new Error(\"[SDK][Curation] mark needs author, permlink and state\");\n }\n const body: Record<string, unknown> = { author, permlink, state };\n if (reason) body.reason = reason;\n if (note) body.note = note;\n if (snooze_until) body.snooze_until = snooze_until;\n if (lane) body.lane = lane;\n return postJson<CurationMarkResponse>(\"/mark\", code, body, \"set mark\");\n}\n\nexport function curationMarkClearRequest(\n code: string | undefined,\n input: { author: string; permlink: string }\n): Promise<CurationMarkClearResponse> {\n if (!input.author || !input.permlink) {\n throw new Error(\"[SDK][Curation] mark-clear needs author and permlink\");\n }\n return postJson<CurationMarkClearResponse>(\n \"/mark-clear\",\n code,\n { author: input.author, permlink: input.permlink },\n \"clear mark\"\n );\n}\n\nexport function curationMyMarksRequest(\n code: string | undefined,\n params: CurationMyMarksParams = {},\n signal?: AbortSignal\n): Promise<CurationMyMarksResponse> {\n const body: Record<string, unknown> = {};\n if (params.state) body.state = params.state;\n if (params.cursor) body.cursor = params.cursor;\n if (params.limit) body.limit = params.limit;\n return postJson<CurationMyMarksResponse>(\"/marks\", code, body, \"fetch my marks\", signal, hasItems);\n}\n\nexport function curationCursorRequest(\n code: string | undefined,\n input: CurationCursorInput\n): Promise<CurationCursorResponse> {\n if (!Number.isFinite(input.post_id) || !input.action) {\n throw new Error(\"[SDK][Curation] cursor needs post_id and action\");\n }\n const body: Record<string, unknown> = { post_id: input.post_id, action: input.action };\n if (input.reason) body.reason = input.reason;\n return postJson<CurationCursorResponse>(\"/cursor\", code, body, \"move cursor\");\n}\n\nconst TRX_ID_RE = /^[0-9a-f]{40}$/;\n\nexport function curationRecommendMetaRequest(\n code: string | undefined,\n input: CurationRecommendMetaInput\n): Promise<{ ok: boolean }> {\n const { author, permlink, trx_id, ua_class } = input;\n if (!author || !permlink || !ua_class) {\n throw new Error(\"[SDK][Curation] recommend-meta needs author, permlink and ua_class\");\n }\n const body: Record<string, unknown> = { author, permlink, ua_class };\n // Optional and informational: only a well-formed id travels, so a path that\n // returned an odd shape never turns the ping into a 400.\n if (typeof trx_id === \"string\" && TRX_ID_RE.test(trx_id)) body.trx_id = trx_id;\n return postJson<{ ok: boolean }>(\"/recommend-meta\", code, body, \"send recommendation meta\");\n}\n\nexport function curationDismissRecoRequest(\n code: string | undefined,\n input: CurationDismissRecoInput\n): Promise<CurationDismissRecoResponse> {\n if (!input.author || !input.permlink || !input.action) {\n throw new Error(\"[SDK][Curation] recommendation-dismiss needs author, permlink and action\");\n }\n return postJson<CurationDismissRecoResponse>(\n \"/recommendation-dismiss\",\n code,\n { author: input.author, permlink: input.permlink, action: input.action },\n \"dismiss recommendation\"\n );\n}\n"]}
@@ -1,2 +1,2 @@
1
- import {k}from'./chunk-4DTETBSG.js';import {a}from'./chunk-HEILHNSR.js';import {queryOptions}from'@tanstack/react-query';function y(r,e){return queryOptions({queryKey:a.curation.rosterAdmin(r),queryFn:({signal:n})=>k(e,n),enabled:!!r&&!!e,staleTime:6e4})}export{y as a};//# sourceMappingURL=chunk-A7EC46DB.js.map
2
- //# sourceMappingURL=chunk-A7EC46DB.js.map
1
+ import {k}from'./chunk-HBIRNFVS.js';import {a}from'./chunk-HEILHNSR.js';import {queryOptions}from'@tanstack/react-query';function y(r,e){return queryOptions({queryKey:a.curation.rosterAdmin(r),queryFn:({signal:n})=>k(e,n),enabled:!!r&&!!e,staleTime:6e4})}export{y as a};//# sourceMappingURL=chunk-IZAIV6WY.js.map
2
+ //# sourceMappingURL=chunk-IZAIV6WY.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/modules/curation/queries/get-curation-roster-admin-query-options.ts"],"names":["getCurationRosterAdminQueryOptions","username","code","queryOptions","QueryKeys","signal","curationRosterListRequest"],"mappings":"yHASO,SAASA,CAAAA,CACdC,EACAC,CAAAA,CACA,CACA,OAAOC,YAAAA,CAAa,CAClB,QAAA,CAAUC,CAAAA,CAAU,QAAA,CAAS,WAAA,CAAYH,CAAQ,CAAA,CACjD,OAAA,CAAS,CAAC,CAAE,OAAAI,CAAO,CAAA,GAAMC,CAAAA,CAA0BJ,CAAAA,CAAMG,CAAM,CAAA,CAC/D,OAAA,CAAS,CAAC,CAACJ,GAAY,CAAC,CAACC,EACzB,SAAA,CAAW,GACb,CAAC,CACH","file":"chunk-A7EC46DB.js","sourcesContent":["import { queryOptions } from \"@tanstack/react-query\";\nimport { QueryKeys } from \"@/modules/core\";\nimport { curationRosterListRequest } from \"../requests\";\n\n/**\n * The admin view of the roster: notes, who added whom, and the retired rows the\n * public roster hides. Admin only upstream, so it is keyed by the viewer and\n * never shares a cache entry with the public roster query.\n */\nexport function getCurationRosterAdminQueryOptions(\n username: string | undefined,\n code: string | undefined\n) {\n return queryOptions({\n queryKey: QueryKeys.curation.rosterAdmin(username),\n queryFn: ({ signal }) => curationRosterListRequest(code, signal),\n enabled: !!username && !!code,\n staleTime: 60_000,\n });\n}\n"]}
1
+ {"version":3,"sources":["../../src/modules/curation/queries/get-curation-roster-admin-query-options.ts"],"names":["getCurationRosterAdminQueryOptions","username","code","queryOptions","QueryKeys","signal","curationRosterListRequest"],"mappings":"yHASO,SAASA,CAAAA,CACdC,EACAC,CAAAA,CACA,CACA,OAAOC,YAAAA,CAAa,CAClB,QAAA,CAAUC,CAAAA,CAAU,QAAA,CAAS,WAAA,CAAYH,CAAQ,CAAA,CACjD,OAAA,CAAS,CAAC,CAAE,OAAAI,CAAO,CAAA,GAAMC,CAAAA,CAA0BJ,CAAAA,CAAMG,CAAM,CAAA,CAC/D,OAAA,CAAS,CAAC,CAACJ,GAAY,CAAC,CAACC,EACzB,SAAA,CAAW,GACb,CAAC,CACH","file":"chunk-IZAIV6WY.js","sourcesContent":["import { queryOptions } from \"@tanstack/react-query\";\nimport { QueryKeys } from \"@/modules/core\";\nimport { curationRosterListRequest } from \"../requests\";\n\n/**\n * The admin view of the roster: notes, who added whom, and the retired rows the\n * public roster hides. Admin only upstream, so it is keyed by the viewer and\n * never shares a cache entry with the public roster query.\n */\nexport function getCurationRosterAdminQueryOptions(\n username: string | undefined,\n code: string | undefined\n) {\n return queryOptions({\n queryKey: QueryKeys.curation.rosterAdmin(username),\n queryFn: ({ signal }) => curationRosterListRequest(code, signal),\n enabled: !!username && !!code,\n staleTime: 60_000,\n });\n}\n"]}
@@ -1,2 +1,2 @@
1
- import {e}from'./chunk-4DTETBSG.js';import {a}from'./chunk-HEILHNSR.js';import {queryOptions}from'@tanstack/react-query';function m(){return queryOptions({queryKey:a.curation.roster(),queryFn:({signal:e$1})=>e(e$1),staleTime:6e5})}export{m as a};//# sourceMappingURL=chunk-LM7BVTOQ.js.map
2
- //# sourceMappingURL=chunk-LM7BVTOQ.js.map
1
+ import {e}from'./chunk-HBIRNFVS.js';import {a}from'./chunk-HEILHNSR.js';import {queryOptions}from'@tanstack/react-query';function m(){return queryOptions({queryKey:a.curation.roster(),queryFn:({signal:e$1})=>e(e$1),staleTime:6e5})}export{m as a};//# sourceMappingURL=chunk-JQBX6M24.js.map
2
+ //# sourceMappingURL=chunk-JQBX6M24.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/modules/curation/queries/get-curation-roster-query-options.ts"],"names":["getCurationRosterQueryOptions","queryOptions","QueryKeys","signal","fetchCurationRoster"],"mappings":"yHAKO,SAASA,CAAAA,EAAgC,CAC9C,OAAOC,YAAAA,CAAa,CAClB,QAAA,CAAUC,CAAAA,CAAU,QAAA,CAAS,MAAA,GAC7B,OAAA,CAAS,CAAC,CAAE,MAAA,CAAAC,GAAO,CAAA,GAAMC,CAAAA,CAAoBD,GAAM,CAAA,CACnD,SAAA,CAAW,GACb,CAAC,CACH","file":"chunk-LM7BVTOQ.js","sourcesContent":["import { queryOptions } from \"@tanstack/react-query\";\nimport { QueryKeys } from \"@/modules/core\";\nimport { fetchCurationRoster } from \"../requests\";\n\n/** Curator roster (route 3): usernames and roles. Changes rarely; 10 minutes shared. */\nexport function getCurationRosterQueryOptions() {\n return queryOptions({\n queryKey: QueryKeys.curation.roster(),\n queryFn: ({ signal }) => fetchCurationRoster(signal),\n staleTime: 600_000,\n });\n}\n"]}
1
+ {"version":3,"sources":["../../src/modules/curation/queries/get-curation-roster-query-options.ts"],"names":["getCurationRosterQueryOptions","queryOptions","QueryKeys","signal","fetchCurationRoster"],"mappings":"yHAKO,SAASA,CAAAA,EAAgC,CAC9C,OAAOC,YAAAA,CAAa,CAClB,QAAA,CAAUC,CAAAA,CAAU,QAAA,CAAS,MAAA,GAC7B,OAAA,CAAS,CAAC,CAAE,MAAA,CAAAC,GAAO,CAAA,GAAMC,CAAAA,CAAoBD,GAAM,CAAA,CACnD,SAAA,CAAW,GACb,CAAC,CACH","file":"chunk-JQBX6M24.js","sourcesContent":["import { queryOptions } from \"@tanstack/react-query\";\nimport { QueryKeys } from \"@/modules/core\";\nimport { fetchCurationRoster } from \"../requests\";\n\n/** Curator roster (route 3): usernames and roles. Changes rarely; 10 minutes shared. */\nexport function getCurationRosterQueryOptions() {\n return queryOptions({\n queryKey: QueryKeys.curation.roster(),\n queryFn: ({ signal }) => fetchCurationRoster(signal),\n staleTime: 600_000,\n });\n}\n"]}
@@ -1,2 +1,2 @@
1
- import {d}from'./chunk-4DTETBSG.js';import {a}from'./chunk-HEILHNSR.js';import {queryOptions}from'@tanstack/react-query';function s(){return queryOptions({queryKey:a.curation.status(),queryFn:({signal:e})=>d(e),staleTime:15e3})}export{s as a};//# sourceMappingURL=chunk-RYI4O7QH.js.map
2
- //# sourceMappingURL=chunk-RYI4O7QH.js.map
1
+ import {d}from'./chunk-HBIRNFVS.js';import {a}from'./chunk-HEILHNSR.js';import {queryOptions}from'@tanstack/react-query';function s(){return queryOptions({queryKey:a.curation.status(),queryFn:({signal:e})=>d(e),staleTime:15e3})}export{s as a};//# sourceMappingURL=chunk-KSQXXIUM.js.map
2
+ //# sourceMappingURL=chunk-KSQXXIUM.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/modules/curation/queries/get-curation-status-query-options.ts"],"names":["getCurationStatusQueryOptions","queryOptions","QueryKeys","signal","fetchCurationStatus"],"mappings":"yHASO,SAASA,CAAAA,EAAgC,CAC9C,OAAOC,YAAAA,CAAa,CAClB,QAAA,CAAUC,CAAAA,CAAU,QAAA,CAAS,MAAA,GAC7B,OAAA,CAAS,CAAC,CAAE,MAAA,CAAAC,CAAO,CAAA,GAAMC,CAAAA,CAAoBD,CAAM,CAAA,CACnD,SAAA,CAAW,IACb,CAAC,CACH","file":"chunk-RYI4O7QH.js","sourcesContent":["import { queryOptions } from \"@tanstack/react-query\";\nimport { QueryKeys } from \"@/modules/core\";\nimport { fetchCurationStatus } from \"../requests\";\n\n/**\n * Desk status (route 2): team cursor, counts, @ecency VP and the mana budget.\n * Public, memoized 15 s at the gateway. The web polls it every 60 s while\n * visible and uses `feed_version` to decide whether page 1 needs a refetch.\n */\nexport function getCurationStatusQueryOptions() {\n return queryOptions({\n queryKey: QueryKeys.curation.status(),\n queryFn: ({ signal }) => fetchCurationStatus(signal),\n staleTime: 15_000,\n });\n}\n"]}
1
+ {"version":3,"sources":["../../src/modules/curation/queries/get-curation-status-query-options.ts"],"names":["getCurationStatusQueryOptions","queryOptions","QueryKeys","signal","fetchCurationStatus"],"mappings":"yHASO,SAASA,CAAAA,EAAgC,CAC9C,OAAOC,YAAAA,CAAa,CAClB,QAAA,CAAUC,CAAAA,CAAU,QAAA,CAAS,MAAA,GAC7B,OAAA,CAAS,CAAC,CAAE,MAAA,CAAAC,CAAO,CAAA,GAAMC,CAAAA,CAAoBD,CAAM,CAAA,CACnD,SAAA,CAAW,IACb,CAAC,CACH","file":"chunk-KSQXXIUM.js","sourcesContent":["import { queryOptions } from \"@tanstack/react-query\";\nimport { QueryKeys } from \"@/modules/core\";\nimport { fetchCurationStatus } from \"../requests\";\n\n/**\n * Desk status (route 2): team cursor, counts, @ecency VP and the mana budget.\n * Public, memoized 15 s at the gateway. The web polls it every 60 s while\n * visible and uses `feed_version` to decide whether page 1 needs a refetch.\n */\nexport function getCurationStatusQueryOptions() {\n return queryOptions({\n queryKey: QueryKeys.curation.status(),\n queryFn: ({ signal }) => fetchCurationStatus(signal),\n staleTime: 15_000,\n });\n}\n"]}
@@ -1,2 +1,2 @@
1
- import {h}from'./chunk-4DTETBSG.js';import {a as a$1}from'./chunk-HEILHNSR.js';import {queryOptions}from'@tanstack/react-query';var u=/^[a-z0-9.-]{3,16}$/,a=/^[a-z0-9-]{1,255}$/;function m(t,r){let o=u.test(t)&&a.test(r);return queryOptions({queryKey:a$1.curation.post(t,r),queryFn:({signal:i})=>{if(!o)throw new Error("[SDK][Curation] invalid author or permlink");return h(t,r,i)},enabled:o,staleTime:15e3})}export{m as a};//# sourceMappingURL=chunk-ZKWRPZHK.js.map
2
- //# sourceMappingURL=chunk-ZKWRPZHK.js.map
1
+ import {h}from'./chunk-HBIRNFVS.js';import {a as a$1}from'./chunk-HEILHNSR.js';import {queryOptions}from'@tanstack/react-query';var u=/^[a-z0-9.-]{3,16}$/,a=/^[a-z0-9-]{1,255}$/;function m(t,r){let o=u.test(t)&&a.test(r);return queryOptions({queryKey:a$1.curation.post(t,r),queryFn:({signal:i})=>{if(!o)throw new Error("[SDK][Curation] invalid author or permlink");return h(t,r,i)},enabled:o,staleTime:15e3})}export{m as a};//# sourceMappingURL=chunk-R4TN3IDN.js.map
2
+ //# sourceMappingURL=chunk-R4TN3IDN.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/modules/curation/queries/get-curation-post-query-options.ts"],"names":["ACCOUNT_RE","PERMLINK_RE","getCurationPostQueryOptions","author","permlink","valid","queryOptions","QueryKeys","signal","fetchCurationPost"],"mappings":"gIAIA,IAAMA,CAAAA,CAAa,oBAAA,CACbC,CAAAA,CAAc,oBAAA,CAQb,SAASC,CAAAA,CAA4BC,CAAAA,CAAgBC,CAAAA,CAAkB,CAC5E,IAAMC,CAAAA,CAAQL,CAAAA,CAAW,IAAA,CAAKG,CAAM,CAAA,EAAKF,CAAAA,CAAY,IAAA,CAAKG,CAAQ,CAAA,CAElE,OAAOE,YAAAA,CAAa,CAClB,QAAA,CAAUC,GAAAA,CAAU,QAAA,CAAS,IAAA,CAAKJ,CAAAA,CAAQC,CAAQ,CAAA,CAClD,OAAA,CAAS,CAAC,CAAE,MAAA,CAAAI,CAAO,CAAA,GAAM,CAGvB,GAAI,CAACH,CAAAA,CACH,MAAM,IAAI,KAAA,CAAM,4CAA4C,CAAA,CAE9D,OAAOI,CAAAA,CAAkBN,CAAAA,CAAQC,CAAAA,CAAUI,CAAM,CACnD,CAAA,CACA,OAAA,CAASH,CAAAA,CACT,SAAA,CAAW,IACb,CAAC,CACH","file":"chunk-ZKWRPZHK.js","sourcesContent":["import { queryOptions } from \"@tanstack/react-query\";\nimport { QueryKeys } from \"@/modules/core\";\nimport { fetchCurationPost } from \"../requests\";\n\nconst ACCOUNT_RE = /^[a-z0-9.-]{3,16}$/;\nconst PERMLINK_RE = /^[a-z0-9-]{1,255}$/;\n\n/**\n * One post's public desk row plus its recommenders (route 5). A viewer finds\n * their own recommendation state by their username in `recommenders`, so no\n * authed read exists. Memoized 15 s at the gateway, which is why a recommender's\n * own row is optimistic and polls this with backoff.\n */\nexport function getCurationPostQueryOptions(author: string, permlink: string) {\n const valid = ACCOUNT_RE.test(author) && PERMLINK_RE.test(permlink);\n\n return queryOptions({\n queryKey: QueryKeys.curation.post(author, permlink),\n queryFn: ({ signal }) => {\n // Guarded twice: `enabled` only gates automatic fetching, a prefetch\n // still runs the queryFn.\n if (!valid) {\n throw new Error(\"[SDK][Curation] invalid author or permlink\");\n }\n return fetchCurationPost(author, permlink, signal);\n },\n enabled: valid,\n staleTime: 15_000,\n });\n}\n"]}
1
+ {"version":3,"sources":["../../src/modules/curation/queries/get-curation-post-query-options.ts"],"names":["ACCOUNT_RE","PERMLINK_RE","getCurationPostQueryOptions","author","permlink","valid","queryOptions","QueryKeys","signal","fetchCurationPost"],"mappings":"gIAIA,IAAMA,CAAAA,CAAa,oBAAA,CACbC,CAAAA,CAAc,oBAAA,CAQb,SAASC,CAAAA,CAA4BC,CAAAA,CAAgBC,CAAAA,CAAkB,CAC5E,IAAMC,CAAAA,CAAQL,CAAAA,CAAW,IAAA,CAAKG,CAAM,CAAA,EAAKF,CAAAA,CAAY,IAAA,CAAKG,CAAQ,CAAA,CAElE,OAAOE,YAAAA,CAAa,CAClB,QAAA,CAAUC,GAAAA,CAAU,QAAA,CAAS,IAAA,CAAKJ,CAAAA,CAAQC,CAAQ,CAAA,CAClD,OAAA,CAAS,CAAC,CAAE,MAAA,CAAAI,CAAO,CAAA,GAAM,CAGvB,GAAI,CAACH,CAAAA,CACH,MAAM,IAAI,KAAA,CAAM,4CAA4C,CAAA,CAE9D,OAAOI,CAAAA,CAAkBN,CAAAA,CAAQC,CAAAA,CAAUI,CAAM,CACnD,CAAA,CACA,OAAA,CAASH,CAAAA,CACT,SAAA,CAAW,IACb,CAAC,CACH","file":"chunk-R4TN3IDN.js","sourcesContent":["import { queryOptions } from \"@tanstack/react-query\";\nimport { QueryKeys } from \"@/modules/core\";\nimport { fetchCurationPost } from \"../requests\";\n\nconst ACCOUNT_RE = /^[a-z0-9.-]{3,16}$/;\nconst PERMLINK_RE = /^[a-z0-9-]{1,255}$/;\n\n/**\n * One post's public desk row plus its recommenders (route 5). A viewer finds\n * their own recommendation state by their username in `recommenders`, so no\n * authed read exists. Memoized 15 s at the gateway, which is why a recommender's\n * own row is optimistic and polls this with backoff.\n */\nexport function getCurationPostQueryOptions(author: string, permlink: string) {\n const valid = ACCOUNT_RE.test(author) && PERMLINK_RE.test(permlink);\n\n return queryOptions({\n queryKey: QueryKeys.curation.post(author, permlink),\n queryFn: ({ signal }) => {\n // Guarded twice: `enabled` only gates automatic fetching, a prefetch\n // still runs the queryFn.\n if (!valid) {\n throw new Error(\"[SDK][Curation] invalid author or permlink\");\n }\n return fetchCurationPost(author, permlink, signal);\n },\n enabled: valid,\n staleTime: 15_000,\n });\n}\n"]}
@@ -1,2 +1,2 @@
1
- import {b,c as c$1}from'./chunk-4DTETBSG.js';import {c}from'./chunk-YNRDVQAQ.js';import {a}from'./chunk-HEILHNSR.js';import {infiniteQueryOptions}from'@tanstack/react-query';var l=25,P=1e4;function p(e,t){let i=new Set,n=false,r=e.pages.map(o=>{let a=o.items.filter(g=>{let u=t(g);return i.has(u)?(n=true,false):(i.add(u),true)});return a.length===o.items.length?o:{...o,items:a}});return n?{...e,pages:r}:e}function y(e){return p(e,t=>t.post_id)}function C(e){return c(y(e))}function x(e={}){let t=e.limit??l,i=b({...e,limit:t});return infiniteQueryOptions({queryKey:a.curation.feed(i),initialPageParam:void 0,queryFn:({pageParam:n,signal:r})=>c$1({...e,limit:t},n,r),getNextPageParam:n=>!n||n.items.length<t?void 0:n.items[n.items.length-1]?._cursor??n.next_cursor??void 0,select:C,staleTime:P})}export{l as a,P as b,p as c,y as d,C as e,x as f};//# sourceMappingURL=chunk-ISEY5355.js.map
2
- //# sourceMappingURL=chunk-ISEY5355.js.map
1
+ import {b,c as c$1}from'./chunk-HBIRNFVS.js';import {c}from'./chunk-YNRDVQAQ.js';import {a}from'./chunk-HEILHNSR.js';import {infiniteQueryOptions}from'@tanstack/react-query';var l=25,P=1e4;function p(e,t){let i=new Set,n=false,r=e.pages.map(o=>{let a=o.items.filter(g=>{let u=t(g);return i.has(u)?(n=true,false):(i.add(u),true)});return a.length===o.items.length?o:{...o,items:a}});return n?{...e,pages:r}:e}function y(e){return p(e,t=>t.post_id)}function C(e){return c(y(e))}function x(e={}){let t=e.limit??l,i=b({...e,limit:t});return infiniteQueryOptions({queryKey:a.curation.feed(i),initialPageParam:void 0,queryFn:({pageParam:n,signal:r})=>c$1({...e,limit:t},n,r),getNextPageParam:n=>!n||n.items.length<t?void 0:n.items[n.items.length-1]?._cursor??n.next_cursor??void 0,select:C,staleTime:P})}export{l as a,P as b,p as c,y as d,C as e,x as f};//# sourceMappingURL=chunk-Y2O7DW46.js.map
2
+ //# sourceMappingURL=chunk-Y2O7DW46.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/modules/curation/queries/get-curation-feed-infinite-query-options.ts"],"names":["CURATION_FEED_PAGE_SIZE","CURATION_FEED_STALE_MS","dedupePagesBy","data","keyOf","seen","changed","pages","page","items","row","key","dedupeCurationPages","selectCurationFeedPages","maskDmcaCurationPages","getCurationFeedInfiniteQueryOptions","params","limit","normalized","normalizeCurationParams","infiniteQueryOptions","QueryKeys","pageParam","signal","fetchCurationFeedPage","lastPage"],"mappings":"kLAMaA,CAAAA,CAA0B,EAAA,CAC1BC,EAAyB,IAQ/B,SAASC,CAAAA,CACdC,CAAAA,CACAC,EAC8B,CAC9B,IAAMC,EAAO,IAAI,GAAA,CACbC,EAAU,KAAA,CACRC,CAAAA,CAAQJ,CAAAA,CAAK,KAAA,CAAM,IAAKK,CAAAA,EAAS,CACrC,IAAMC,CAAAA,CAAQD,CAAAA,CAAK,MAAM,MAAA,CAAQE,CAAAA,EAAQ,CACvC,IAAMC,EAAMP,CAAAA,CAAMM,CAAG,EACrB,OAAIL,CAAAA,CAAK,IAAIM,CAAG,CAAA,EACdL,CAAAA,CAAU,IAAA,CACH,QAETD,CAAAA,CAAK,GAAA,CAAIM,CAAG,CAAA,CACL,IAAA,CACT,CAAC,CAAA,CACD,OAAOF,CAAAA,CAAM,MAAA,GAAWD,EAAK,KAAA,CAAM,MAAA,CAASA,EAAO,CAAE,GAAGA,EAAM,KAAA,CAAAC,CAAM,CACtE,CAAC,EACD,OAAOH,CAAAA,CAAU,CAAE,GAAGH,CAAAA,CAAM,MAAAI,CAAM,CAAA,CAAIJ,CACxC,CAGO,SAASS,EACdT,CAAAA,CAC8B,CAC9B,OAAOD,CAAAA,CAAcC,CAAAA,CAAOO,GAAQA,CAAAA,CAAI,OAAO,CACjD,CAgBO,SAASG,CAAAA,CACdV,CAAAA,CAC8B,CAC9B,OAAOW,CAAAA,CAAsBF,EAAoBT,CAAI,CAAC,CACxD,CAYO,SAASY,CAAAA,CAAoCC,CAAAA,CAA6B,EAAC,CAAG,CACnF,IAAMC,CAAAA,CAAQD,CAAAA,CAAO,KAAA,EAAShB,CAAAA,CACxBkB,EAAaC,CAAAA,CAAwB,CAAE,GAAGH,CAAAA,CAAQ,KAAA,CAAAC,CAAM,CAAC,CAAA,CAE/D,OAAOG,oBAAAA,CAAqB,CAC1B,QAAA,CAAUC,CAAAA,CAAU,SAAS,IAAA,CAAKH,CAAU,EAC5C,gBAAA,CAAkB,MAAA,CAClB,OAAA,CAAS,CAAC,CAAE,SAAA,CAAAI,CAAAA,CAAW,OAAAC,CAAO,CAAA,GAAMC,IAAsB,CAAE,GAAGR,CAAAA,CAAQ,KAAA,CAAAC,CAAM,CAAA,CAAGK,CAAAA,CAAWC,CAAM,CAAA,CACjG,gBAAA,CAAmBE,GACb,CAACA,CAAAA,EAAYA,CAAAA,CAAS,KAAA,CAAM,OAASR,CAAAA,CACvC,MAAA,CAEoCQ,EAAS,KAAA,CAAMA,CAAAA,CAAS,MAAM,MAAA,CAAS,CAAC,GACjE,OAAA,EAAWA,CAAAA,CAAS,aAAe,MAAA,CAElD,MAAA,CAAQZ,EACR,SAAA,CAAWZ,CACb,CAAC,CACH","file":"chunk-ISEY5355.js","sourcesContent":["import { infiniteQueryOptions, type InfiniteData } from \"@tanstack/react-query\";\nimport { QueryKeys } from \"@/modules/core\";\nimport { maskDmcaCurationPages } from \"../dmca\";\nimport { fetchCurationFeedPage, normalizeCurationParams } from \"../requests\";\nimport type { CurationFeedPage, CurationFeedParams, CurationRow } from \"../types\";\n\nexport const CURATION_FEED_PAGE_SIZE = 25;\nexport const CURATION_FEED_STALE_MS = 10_000;\n\n/**\n * Drops rows whose key already appeared on an earlier page. Needed for the\n * live-keyset `unique` order (a row whose count rose between two pages repeats),\n * harmless for the immutable chronological orders. Untouched pages keep their\n * identity so memoized rows do not re-render.\n */\nexport function dedupePagesBy<TPage extends { items: unknown[] }>(\n data: InfiniteData<TPage, unknown>,\n keyOf: (item: TPage[\"items\"][number]) => string | number\n): InfiniteData<TPage, unknown> {\n const seen = new Set<string | number>();\n let changed = false;\n const pages = data.pages.map((page) => {\n const items = page.items.filter((row) => {\n const key = keyOf(row);\n if (seen.has(key)) {\n changed = true;\n return false;\n }\n seen.add(key);\n return true;\n });\n return items.length === page.items.length ? page : { ...page, items };\n });\n return changed ? { ...data, pages } : data;\n}\n\n/** Feed pages dedupe by `post_id`. */\nexport function dedupeCurationPages<TPage extends { items: Array<{ post_id: number }> }>(\n data: InfiniteData<TPage, unknown>\n): InfiniteData<TPage, unknown> {\n return dedupePagesBy(data, (row) => row.post_id);\n}\n\ninterface SelectableFeedRow {\n post_id: number;\n author: string;\n permlink: string;\n title: string;\n summary?: string | null;\n first_image?: string | null;\n}\n\n/**\n * The select every desk feed shares: dedupe by `post_id`, then blank the rows\n * on the takedown list. The roster feed (web owned, because its queryFn needs\n * a fresh token) uses it too, so both feeds hide the same rows.\n */\nexport function selectCurationFeedPages<TPage extends { items: SelectableFeedRow[] }>(\n data: InfiniteData<TPage, unknown>\n): InfiniteData<TPage, unknown> {\n return maskDmcaCurationPages(dedupeCurationPages(data));\n}\n\n/**\n * Public curation feed (route 1), keyset paginated.\n *\n * `_cursor` on the last row is opaque: it encodes the order's key (`created`\n * and `post_id` for the chronological sorts, the recommender pair for `unique`,\n * the hash pair for `random`). A short page ends the list. No `refetchInterval`\n * (React Query would refetch every loaded page) and no `initialData` (the web\n * client's `refetchOnMount: false` would then never fetch page 1): the web polls\n * `status` and refetches page 1 only when `feed_version` changes.\n */\nexport function getCurationFeedInfiniteQueryOptions(params: CurationFeedParams = {}) {\n const limit = params.limit ?? CURATION_FEED_PAGE_SIZE;\n const normalized = normalizeCurationParams({ ...params, limit });\n\n return infiniteQueryOptions({\n queryKey: QueryKeys.curation.feed(normalized),\n initialPageParam: undefined as string | undefined,\n queryFn: ({ pageParam, signal }) => fetchCurationFeedPage({ ...params, limit }, pageParam, signal),\n getNextPageParam: (lastPage: CurationFeedPage): string | undefined => {\n if (!lastPage || lastPage.items.length < limit) {\n return undefined;\n }\n const last: CurationRow | undefined = lastPage.items[lastPage.items.length - 1];\n return last?._cursor ?? lastPage.next_cursor ?? undefined;\n },\n select: selectCurationFeedPages,\n staleTime: CURATION_FEED_STALE_MS,\n });\n}\n"]}
1
+ {"version":3,"sources":["../../src/modules/curation/queries/get-curation-feed-infinite-query-options.ts"],"names":["CURATION_FEED_PAGE_SIZE","CURATION_FEED_STALE_MS","dedupePagesBy","data","keyOf","seen","changed","pages","page","items","row","key","dedupeCurationPages","selectCurationFeedPages","maskDmcaCurationPages","getCurationFeedInfiniteQueryOptions","params","limit","normalized","normalizeCurationParams","infiniteQueryOptions","QueryKeys","pageParam","signal","fetchCurationFeedPage","lastPage"],"mappings":"kLAMaA,CAAAA,CAA0B,EAAA,CAC1BC,EAAyB,IAQ/B,SAASC,CAAAA,CACdC,CAAAA,CACAC,EAC8B,CAC9B,IAAMC,EAAO,IAAI,GAAA,CACbC,EAAU,KAAA,CACRC,CAAAA,CAAQJ,CAAAA,CAAK,KAAA,CAAM,IAAKK,CAAAA,EAAS,CACrC,IAAMC,CAAAA,CAAQD,CAAAA,CAAK,MAAM,MAAA,CAAQE,CAAAA,EAAQ,CACvC,IAAMC,EAAMP,CAAAA,CAAMM,CAAG,EACrB,OAAIL,CAAAA,CAAK,IAAIM,CAAG,CAAA,EACdL,CAAAA,CAAU,IAAA,CACH,QAETD,CAAAA,CAAK,GAAA,CAAIM,CAAG,CAAA,CACL,IAAA,CACT,CAAC,CAAA,CACD,OAAOF,CAAAA,CAAM,MAAA,GAAWD,EAAK,KAAA,CAAM,MAAA,CAASA,EAAO,CAAE,GAAGA,EAAM,KAAA,CAAAC,CAAM,CACtE,CAAC,EACD,OAAOH,CAAAA,CAAU,CAAE,GAAGH,CAAAA,CAAM,MAAAI,CAAM,CAAA,CAAIJ,CACxC,CAGO,SAASS,EACdT,CAAAA,CAC8B,CAC9B,OAAOD,CAAAA,CAAcC,CAAAA,CAAOO,GAAQA,CAAAA,CAAI,OAAO,CACjD,CAgBO,SAASG,CAAAA,CACdV,CAAAA,CAC8B,CAC9B,OAAOW,CAAAA,CAAsBF,EAAoBT,CAAI,CAAC,CACxD,CAYO,SAASY,CAAAA,CAAoCC,CAAAA,CAA6B,EAAC,CAAG,CACnF,IAAMC,CAAAA,CAAQD,CAAAA,CAAO,KAAA,EAAShB,CAAAA,CACxBkB,EAAaC,CAAAA,CAAwB,CAAE,GAAGH,CAAAA,CAAQ,KAAA,CAAAC,CAAM,CAAC,CAAA,CAE/D,OAAOG,oBAAAA,CAAqB,CAC1B,QAAA,CAAUC,CAAAA,CAAU,SAAS,IAAA,CAAKH,CAAU,EAC5C,gBAAA,CAAkB,MAAA,CAClB,OAAA,CAAS,CAAC,CAAE,SAAA,CAAAI,CAAAA,CAAW,OAAAC,CAAO,CAAA,GAAMC,IAAsB,CAAE,GAAGR,CAAAA,CAAQ,KAAA,CAAAC,CAAM,CAAA,CAAGK,CAAAA,CAAWC,CAAM,CAAA,CACjG,gBAAA,CAAmBE,GACb,CAACA,CAAAA,EAAYA,CAAAA,CAAS,KAAA,CAAM,OAASR,CAAAA,CACvC,MAAA,CAEoCQ,EAAS,KAAA,CAAMA,CAAAA,CAAS,MAAM,MAAA,CAAS,CAAC,GACjE,OAAA,EAAWA,CAAAA,CAAS,aAAe,MAAA,CAElD,MAAA,CAAQZ,EACR,SAAA,CAAWZ,CACb,CAAC,CACH","file":"chunk-Y2O7DW46.js","sourcesContent":["import { infiniteQueryOptions, type InfiniteData } from \"@tanstack/react-query\";\nimport { QueryKeys } from \"@/modules/core\";\nimport { maskDmcaCurationPages } from \"../dmca\";\nimport { fetchCurationFeedPage, normalizeCurationParams } from \"../requests\";\nimport type { CurationFeedPage, CurationFeedParams, CurationRow } from \"../types\";\n\nexport const CURATION_FEED_PAGE_SIZE = 25;\nexport const CURATION_FEED_STALE_MS = 10_000;\n\n/**\n * Drops rows whose key already appeared on an earlier page. Needed for the\n * live-keyset `unique` order (a row whose count rose between two pages repeats),\n * harmless for the immutable chronological orders. Untouched pages keep their\n * identity so memoized rows do not re-render.\n */\nexport function dedupePagesBy<TPage extends { items: unknown[] }>(\n data: InfiniteData<TPage, unknown>,\n keyOf: (item: TPage[\"items\"][number]) => string | number\n): InfiniteData<TPage, unknown> {\n const seen = new Set<string | number>();\n let changed = false;\n const pages = data.pages.map((page) => {\n const items = page.items.filter((row) => {\n const key = keyOf(row);\n if (seen.has(key)) {\n changed = true;\n return false;\n }\n seen.add(key);\n return true;\n });\n return items.length === page.items.length ? page : { ...page, items };\n });\n return changed ? { ...data, pages } : data;\n}\n\n/** Feed pages dedupe by `post_id`. */\nexport function dedupeCurationPages<TPage extends { items: Array<{ post_id: number }> }>(\n data: InfiniteData<TPage, unknown>\n): InfiniteData<TPage, unknown> {\n return dedupePagesBy(data, (row) => row.post_id);\n}\n\ninterface SelectableFeedRow {\n post_id: number;\n author: string;\n permlink: string;\n title: string;\n summary?: string | null;\n first_image?: string | null;\n}\n\n/**\n * The select every desk feed shares: dedupe by `post_id`, then blank the rows\n * on the takedown list. The roster feed (web owned, because its queryFn needs\n * a fresh token) uses it too, so both feeds hide the same rows.\n */\nexport function selectCurationFeedPages<TPage extends { items: SelectableFeedRow[] }>(\n data: InfiniteData<TPage, unknown>\n): InfiniteData<TPage, unknown> {\n return maskDmcaCurationPages(dedupeCurationPages(data));\n}\n\n/**\n * Public curation feed (route 1), keyset paginated.\n *\n * `_cursor` on the last row is opaque: it encodes the order's key (`created`\n * and `post_id` for the chronological sorts, the recommender pair for `unique`,\n * the hash pair for `random`). A short page ends the list. No `refetchInterval`\n * (React Query would refetch every loaded page) and no `initialData` (the web\n * client's `refetchOnMount: false` would then never fetch page 1): the web polls\n * `status` and refetches page 1 only when `feed_version` changes.\n */\nexport function getCurationFeedInfiniteQueryOptions(params: CurationFeedParams = {}) {\n const limit = params.limit ?? CURATION_FEED_PAGE_SIZE;\n const normalized = normalizeCurationParams({ ...params, limit });\n\n return infiniteQueryOptions({\n queryKey: QueryKeys.curation.feed(normalized),\n initialPageParam: undefined as string | undefined,\n queryFn: ({ pageParam, signal }) => fetchCurationFeedPage({ ...params, limit }, pageParam, signal),\n getNextPageParam: (lastPage: CurationFeedPage): string | undefined => {\n if (!lastPage || lastPage.items.length < limit) {\n return undefined;\n }\n const last: CurationRow | undefined = lastPage.items[lastPage.items.length - 1];\n return last?._cursor ?? lastPage.next_cursor ?? undefined;\n },\n select: selectCurationFeedPages,\n staleTime: CURATION_FEED_STALE_MS,\n });\n}\n"]}
@@ -0,0 +1,2 @@
1
+ var e=["quality","underrated","newcomer","other"],n=["queue","newest","unique","random"],t=["queue","latest","new-authors","recommended","curated","all","excluded"],r=["all","ecency","peakd","other"],o=["12h","full","half","eighth","locked","all"],a=["reviewed","snoozed","flagged","noted"],i=["plagiarism","ai_slop","recycled","image_only","tag_abuse","farming","nsfw_untagged","other"];export{e as a,n as b,t as c,r as d,o as e,a as f,i as g};//# sourceMappingURL=chunk-ZLU6INZR.js.map
2
+ //# sourceMappingURL=chunk-ZLU6INZR.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/modules/curation/types.ts"],"names":["CURATION_REASONS","CURATION_SORTS","CURATION_VIEWS","CURATION_APPS","CURATION_WINDOWS","CURATION_MARK_STATES","CURATION_FLAG_REASONS"],"mappings":"AASO,IAAMA,CAAAA,CAAmB,CAAC,SAAA,CAAW,YAAA,CAAc,UAAA,CAAY,OAAO,CAAA,CAGhEC,CAAAA,CAAiB,CAAC,OAAA,CAAS,QAAA,CAAU,QAAA,CAAU,QAAQ,EAGvDC,CAAAA,CAAiB,CAC5B,OAAA,CACA,QAAA,CACA,aAAA,CACA,aAAA,CACA,SAAA,CACA,KAAA,CACA,UACF,CAAA,CAGaC,CAAAA,CAAgB,CAAC,KAAA,CAAO,QAAA,CAAU,QAAS,OAAO,CAAA,CAGlDC,CAAAA,CAAmB,CAAC,KAAA,CAAO,MAAA,CAAQ,MAAA,CAAQ,QAAA,CAAU,QAAA,CAAU,KAAK,CAAA,CAGpEC,CAAAA,CAAuB,CAAC,UAAA,CAAY,UAAW,SAAA,CAAW,OAAO,CAAA,CAGjEC,CAAAA,CAAwB,CACnC,YAAA,CACA,SAAA,CACA,UAAA,CACA,YAAA,CACA,WAAA,CACA,SAAA,CACA,eAAA,CACA,OACF","file":"chunk-WAIGSUA6.js","sourcesContent":["/**\n * Curation desk types.\n *\n * Shapes mirror the desk routes behind `/private-api/curation-desk/*`. Public\n * rows carry no curator identity; the roster feed and the tick add an `overlay`\n * with marks, signals and flags. The window state (full, half, eighth, locked,\n * paid) is never in a payload: clients derive it from `created` and `payout_at`.\n */\n\nexport const CURATION_REASONS = [\"quality\", \"underrated\", \"newcomer\", \"other\"] as const;\nexport type CurationReason = (typeof CURATION_REASONS)[number];\n\nexport const CURATION_SORTS = [\"queue\", \"newest\", \"unique\", \"random\"] as const;\nexport type CurationSort = (typeof CURATION_SORTS)[number];\n\nexport const CURATION_VIEWS = [\n \"queue\",\n \"latest\",\n \"new-authors\",\n \"recommended\",\n \"curated\",\n \"all\",\n \"excluded\",\n] as const;\nexport type CurationView = (typeof CURATION_VIEWS)[number];\n\nexport const CURATION_APPS = [\"all\", \"ecency\", \"peakd\", \"other\"] as const;\nexport type CurationApp = (typeof CURATION_APPS)[number];\n\nexport const CURATION_WINDOWS = [\"12h\", \"full\", \"half\", \"eighth\", \"locked\", \"all\"] as const;\nexport type CurationWindow = (typeof CURATION_WINDOWS)[number];\n\nexport const CURATION_MARK_STATES = [\"reviewed\", \"snoozed\", \"flagged\", \"noted\"] as const;\nexport type CurationMarkState = (typeof CURATION_MARK_STATES)[number];\n\nexport const CURATION_FLAG_REASONS = [\n \"plagiarism\",\n \"ai_slop\",\n \"recycled\",\n \"image_only\",\n \"tag_abuse\",\n \"farming\",\n \"nsfw_untagged\",\n \"other\",\n] as const;\nexport type CurationFlagReason = (typeof CURATION_FLAG_REASONS)[number];\n\nexport type CurationRole = \"admin\" | \"mod\" | \"curator\" | \"trial\";\n\n/** Filters shared by the public feed (query params) and the roster feed (body). */\nexport interface CurationFeedParams {\n sort?: CurationSort;\n view?: CurationView;\n app?: CurationApp;\n community?: string;\n window?: CurationWindow;\n rep_min?: number;\n rep_max?: number;\n min_words?: number;\n max_words?: number;\n has_images?: boolean;\n new_authors?: boolean;\n recommended?: boolean;\n hide_curated?: boolean;\n limit?: number;\n}\n\n/** Roster-only additions: the random seed and the team-mark predicates. */\nexport interface CurationRosterFeedParams extends CurationFeedParams {\n seed?: string;\n flagged?: boolean;\n hide_reviewed?: boolean;\n hide_snoozed?: boolean;\n}\n\nexport interface CurationTrailedBy {\n curator: string;\n at: string;\n weight: number;\n source: \"erobot_push\" | \"history\" | \"inferred\" | string;\n confirmed: boolean;\n}\n\nexport interface CurationVotedBy {\n voter: string;\n weight: number;\n at: string;\n}\n\n/** Public row (route 1, 4 rows are narrower, route 5 adds recommenders). */\nexport interface CurationRow {\n post_id: number;\n author: string;\n permlink: string;\n title: string;\n created: string;\n app: string | null;\n is_ecency: boolean;\n community: string | null;\n community_title: string | null;\n tags: string[];\n rep: number | null;\n is_new_author: boolean;\n author_post_count: number | null;\n author_created?: string | null;\n word_count: number | null;\n image_count: number;\n first_image: string | null;\n summary: string | null;\n edited_at: string | null;\n edit_count: number;\n votes: number | null;\n pending_payout: number | null;\n pending_payout_est?: number | null;\n payout_at: string | null;\n is_declined?: boolean | null;\n is_gray?: boolean | null;\n rshares_total?: number | null;\n rshares_after_24h?: number | null;\n /** 0 open, 1 curated, 2 dropped */\n state: number;\n trailed_by: CurationTrailedBy | null;\n voted_by: CurationVotedBy[];\n author_trailed_at: string | null;\n /** Set on the hivewatchers unvote path. */\n unvoted_at?: string | null;\n /** Materialization time; with `created` it tells a late row. */\n inserted_at?: string | null;\n recommend_count: number;\n unique_recommenders: number;\n reco_no_meta_count: number;\n /** Opaque keyset cursor for the page that follows this row. */\n _cursor?: string;\n}\n\nexport interface CurationMark {\n curator: string;\n state: CurationMarkState;\n reason?: string | null;\n note?: string | null;\n /**\n * Whether a note body exists. Tick deltas carry this instead of the body,\n * so a delta must never overwrite a note the client already holds.\n */\n has_note?: boolean;\n snooze_until?: string | null;\n updated_at: string;\n}\n\nexport interface CurationSignals {\n /** Whole percents (0-100) as the signals service sends them, never a 0-1 fraction. */\n formulaic?: number | null;\n images?: { hive_hosted?: number; external?: number; total?: number } | null;\n engagement?: { replies_per_day?: number | null } | null;\n /** `n` is how many of the author's own past posts the baseline holds, `driver` the feature that moved most. */\n style?: { alert?: boolean; sigma?: number | null; driver?: string; n?: number } | null;\n /**\n * The detector's read of the post's FIRST image, which is the one rendered as the\n * thumbnail. `over` is the only field to act on; `score` and `classes` are for tuning.\n * A null score means unknown (no image, or the check could not run), never \"clean\".\n */\n nsfw?: {\n score?: number | null;\n class?: string | null;\n over?: boolean;\n classes?: string[];\n note?: string;\n } | null;\n [key: string]: unknown;\n}\n\nexport interface CurationFlags {\n low_rep?: boolean;\n /** The author's reputation has gone negative, which is not the same line as low_rep. */\n negative_rep?: boolean;\n ignorelist?: boolean;\n abuser?: boolean;\n spaminator?: boolean;\n blocked_tag?: boolean;\n /** The post carries Hive's own `nsfw` tag. */\n nsfw?: boolean;\n patch_body?: boolean;\n deleted?: boolean;\n hivewatchers_downvote?: boolean;\n [key: string]: unknown;\n}\n\n/** Roster-only overlay shipped inline with the roster feed and in tick deltas. */\nexport interface CurationOverlay {\n signals: CurationSignals | null;\n flags: CurationFlags;\n excluded_reason: string | null;\n team_mark: CurationMarkState | null;\n team_mark_by: string | null;\n team_snooze_until?: string | null;\n resurfaced_at: string | null;\n /** Set when the roster dismissed the recommendations of this post. */\n reco_dismissed_at?: string | null;\n marks: CurationMark[];\n notes_count: number;\n}\n\nexport type CurationRosterRow = CurationRow & { overlay: CurationOverlay | null };\n\nexport interface CurationTeamCursor {\n post_id: number | null;\n created: string | null;\n set_by?: string;\n set_at?: string;\n}\n\nexport interface CurationActiveCurator {\n username: string;\n last_action_at: string;\n}\n\n/**\n * The narrowing facets a curator was working when they made a mark. Empty means\n * the whole queue. The keys are the roster feed's own params, so a value here has\n * already been through the allow lists the query runs on.\n */\nexport type CurationLane = Partial<{\n /** Present only when it is not the queue order, under which alone a position is a watermark. */\n sort: CurationSort;\n view: string;\n app: CurationApp;\n community: string;\n window: CurationWindow;\n rep_min: number;\n rep_max: number;\n min_words: number;\n max_words: number;\n has_images: boolean;\n new_authors: boolean;\n recommended: boolean;\n flagged: boolean;\n hide_curated: boolean;\n hide_reviewed: boolean;\n hide_snoozed: boolean;\n}>;\n\n/**\n * How far one curator has got, derived from their marks so nobody types it. This\n * is the hand-off curators used to post in Discord.\n *\n * `reviewed_to` is a progress claim rather than a contiguous reviewed prefix: a\n * mark is any of the four states and marks are not made in queue order. It is\n * read, never used to aim anything. `lane` travels with the mark that set the\n * position, so the two always describe the same moment. Roster-only: the public\n * payloads carry no per-curator activity at all.\n */\nexport interface CurationHandoffEntry {\n username: string;\n reviewed_to: string | null;\n reviewed_to_post_id: number | null;\n last_mark_at: string;\n /** Absent for a trial viewer looking at somebody else. */\n marks_24h?: number;\n /**\n * Null is UNKNOWN: a mark from before the desk sent lanes, or one that said\n * nothing. It is never the whole queue, which is `{}`. Absent until the\n * backend that records it is deployed.\n */\n lane?: CurationLane | null;\n}\n\nexport interface CurationFeedPage {\n items: CurationRow[];\n next_cursor: string | null;\n team_cursor: CurationTeamCursor;\n head_lag_seconds: number;\n feed_version: string | null;\n generated_at: string;\n}\n\nexport interface CurationRosterFeedPage {\n items: CurationRosterRow[];\n next_cursor: string | null;\n team_cursor: CurationTeamCursor;\n active_curators: CurationActiveCurator[];\n /** Roster only, and absent until the backend that derives it is deployed. */\n handoff?: CurationHandoffEntry[];\n facets: { communities: Array<{ community: string; title?: string | null; count?: number }> };\n total_estimate: number | null;\n head_lag_seconds: number;\n generated_at: string;\n}\n\nexport interface CurationManaSpent {\n equiv: number;\n trail: number;\n other: number;\n crosscheck: number | null;\n since: string;\n}\n\nexport interface CurationVp {\n account: string;\n percent: number;\n live_percent: number;\n implied_weight: number;\n at: string;\n sustainable_votes_per_day: number;\n regen_votes_per_hour: number;\n reward_fund?: {\n recent_claims: string | number;\n reward_balance: number;\n median_price: number;\n at: string;\n } | null;\n}\n\nexport interface CurationStatus {\n team_cursor: CurationTeamCursor;\n behind_seconds: number | null;\n counts: {\n unreviewed: number;\n curated_24h: number;\n trail_votes_today: { posts: number; comments: number };\n recommended_posts: number;\n };\n /**\n * The application window, carried on status so no page needs a second call to\n * find out whether it may invite anyone. Older desks do not send it.\n */\n applications?: CurationApplicationWindow;\n mana_spent_today: CurationManaSpent | null;\n vp: CurationVp | null;\n head_lag_seconds: number;\n reco_lag_blocks: number | null;\n feed_version: string | null;\n latest_post_id: number | null;\n worker_tick_age_seconds: number | null;\n}\n\n/**\n * The per-curator conditions erobot applies before trailing a vote. The three\n * weights are Hive vote weights (100 = 1%); `trail` overrides the per-role\n * default, and is what `config.followAccounts` used to be.\n */\nexport interface CurationRosterRules {\n min_weight?: number;\n max_weight?: number;\n waves_only_below?: number;\n trail?: boolean;\n}\n\nexport interface CurationRosterEntry {\n username: string;\n role: CurationRole;\n active: boolean;\n rules?: CurationRosterRules | null;\n /** Resolved by the backend, so no client re-implements the per-role default. */\n trail?: boolean;\n}\n\n/**\n * The admin view of a row. These fields are private, so they arrive from the\n * roster-list POST and never from the edge-cached roster GET.\n */\nexport interface CurationRosterAdminEntry extends CurationRosterEntry {\n added_by: string | null;\n added_at: string | null;\n removed_at: string | null;\n note: string | null;\n}\n\nexport interface CurationRoster {\n curators: CurationRosterEntry[];\n updated_at: string;\n}\n\nexport interface CurationRosterAdminList {\n curators: CurationRosterAdminEntry[];\n}\n\n/** Open or closed, with the line shown to a reader while it is closed. */\nexport interface CurationApplicationWindow {\n open: boolean;\n message: string | null;\n /** Only the admin routes return this; status carries the two fields above. */\n updated_at?: string | null;\n}\n\nexport type CurationApplicationState =\n | \"open\"\n | \"shortlisted\"\n | \"accepted\"\n | \"declined\"\n | \"withdrawn\";\n\n/** The three questions the apply form asks, as the desk stores them. */\nexport interface CurationApplicationAnswers {\n motivation: string;\n availability: string;\n pick: string;\n}\n\n/** What an applicant sees of their own application. */\nexport interface CurationApplication {\n id: number;\n username: string;\n answers: CurationApplicationAnswers;\n state: CurationApplicationState;\n created: string;\n updated_at: string;\n decided_at: string | null;\n}\n\n/**\n * The reviewer's view. `snapshot` is the applicant's recommendation record as it\n * stood when they applied, frozen because the live record keeps moving.\n */\nexport interface CurationApplicationAdminEntry extends CurationApplication {\n snapshot: CurationRecommenderStats | null;\n decided_by: string | null;\n admin_note: string | null;\n}\n\nexport interface CurationApplicationMine {\n application: CurationApplication | null;\n window: CurationApplicationWindow;\n /** The viewer's roster role, so the page can say \"you are already a curator\". */\n role: CurationRole | null;\n}\n\nexport interface CurationApplicationList {\n applications: CurationApplicationAdminEntry[];\n counts: Partial<Record<CurationApplicationState, number>>;\n window: CurationApplicationWindow;\n}\n\nexport interface CurationApplicationDecideInput {\n applicant: string;\n /** Only the three a reviewer may set; `open` and `withdrawn` are not decisions. */\n state: \"shortlisted\" | \"accepted\" | \"declined\";\n /** Accepting only. Defaults to `trial` upstream, which is not trailed. */\n role?: Extract<CurationRole, \"trial\" | \"curator\" | \"mod\">;\n note?: string;\n}\n\nexport interface CurationRosterSetInput {\n curator: string;\n role: CurationRole;\n rules?: CurationRosterRules;\n note?: string;\n}\n\nexport interface CurationRecommender {\n username: string;\n rep: number | null;\n reason: CurationReason | null;\n at: string;\n has_meta: boolean;\n is_self?: boolean;\n /**\n * Ordering weight of this recommender, 0.5 to 1.5 with 1.0 neutral. Above\n * 1.0 means curators curated their picks more often than they dismissed\n * them over the window. It changes ordering only, never what is shown.\n */\n precision?: number;\n /** At least 10 recommendations and a precision of 1.2 or more. */\n trusted?: boolean;\n}\n\n/**\n * Route 14: one recommender's 90-day scorecard. An unknown username answers\n * zeros with a neutral precision and `trusted: false`, never a 404, so a name\n * that never recommended anything is not an error state.\n */\nexport interface CurationRecommenderStats {\n username: string;\n window_days: number;\n recommended: number;\n curated: number;\n dismissed: number;\n withdrawn: number;\n precision: number;\n trusted: boolean;\n computed_at: string | null;\n}\n\nexport type CurationReasonsHistogram = Partial<Record<CurationReason, number>>;\n\nexport interface CurationRecommendationItem {\n author: string;\n permlink: string;\n title: string;\n created: string;\n /**\n * The post's cover, the same column the feed row carries. Optional because a\n * desk older than the field answers without it; absent and null both mean no\n * cover, and the caller proxifies before rendering.\n */\n first_image?: string | null;\n recommend_count: number;\n unique_recommenders: number;\n no_meta_count: number;\n reasons: CurationReasonsHistogram;\n recommenders: CurationRecommender[];\n _cursor?: string;\n}\n\nexport interface CurationRecommendationsPage {\n items: CurationRecommendationItem[];\n next_cursor: string | null;\n}\n\nexport type CurationRecommendationsSort = \"unique\" | \"newest\";\n\nexport interface CurationRecommendationsParams {\n sort?: CurationRecommendationsSort;\n limit?: number;\n}\n\n/** Route 5: the public row plus the recommender list, self row included. */\nexport interface CurationPost extends CurationRow {\n recommenders: CurationRecommender[];\n no_meta_count: number;\n reasons: CurationReasonsHistogram;\n}\n\nexport interface CurationTickRequest {\n /** `generated_at` echoed verbatim from the previous response. */\n since: string | null;\n /** Loaded rows that have no overlay yet (at most 100). */\n need: number[];\n /** Visible rows (at most 100). */\n visible: number[];\n}\n\n/**\n * Tick answer. `truncated` says the delta window was too wide to answer in\n * full; it only means something when the request carried a `since`, since a\n * first tick with `since: null` asks for a snapshot, not a window.\n */\nexport interface CurationTickResponse {\n overlay: Array<{ post_id: number } & CurationOverlay>;\n deltas: {\n marks: Array<{ post_id: number } & CurationMark>;\n flags: Array<{ post_id: number; flags: CurationFlags; excluded_reason: string | null }>;\n signals: Array<{ post_id: number; signals: CurationSignals | null }>;\n /**\n * Rows whose curation state moved since the client's own `generated_at`.\n * The overlay carries no state, so without these a page the client keeps\n * holding would render a curated post as open and votable. Optional: a\n * backend that predates it simply sends nothing.\n */\n rows?: Array<\n Pick<CurationRow, \"post_id\" | \"state\" | \"trailed_by\" | \"voted_by\" | \"unvoted_at\">\n >;\n };\n team_cursor: CurationTeamCursor;\n active_curators: CurationActiveCurator[];\n /** Roster only, and absent until the backend that derives it is deployed. */\n handoff?: CurationHandoffEntry[];\n trail_alerts: unknown[];\n generated_at: string;\n truncated: boolean;\n}\n\nexport interface CurationMarkInput {\n author: string;\n permlink: string;\n state: CurationMarkState;\n reason?: string;\n note?: string;\n snooze_until?: string;\n /**\n * The feed params the desk was showing when it made this mark. The hand-off\n * reads a position and its lane off the same mark, so a desk with two tabs on\n * different filters stamps each mark with its own. Paging keys are dropped by\n * the gateway; absent means the lane is unknown, never the whole queue.\n */\n lane?: CurationRosterFeedParams;\n}\n\nexport interface CurationMarkResponse {\n mark: CurationMark | null;\n row: CurationRosterRow;\n}\n\nexport interface CurationMarkClearResponse {\n ok: boolean;\n row: CurationRosterRow;\n}\n\nexport interface CurationMyMarksParams {\n state?: CurationMarkState;\n cursor?: string;\n limit?: number;\n}\n\nexport interface CurationMyMark extends CurationMark {\n post_id: number;\n author: string;\n permlink: string;\n title: string;\n created: string;\n row?: CurationRosterRow | null;\n}\n\nexport interface CurationMyMarksResponse {\n items: CurationMyMark[];\n next_cursor: string | null;\n}\n\nexport type CurationCursorAction = \"advance\" | \"rewind\";\n\nexport interface CurationCursorInput {\n post_id: number;\n action: CurationCursorAction;\n reason?: string;\n}\n\nexport interface CurationCursorResponse {\n team_cursor: CurationTeamCursor;\n moved: boolean;\n swept_count: number | null;\n}\n\nexport type CurationUaClass = \"web\" | \"mobile\";\n\nexport interface CurationRecommendMetaInput {\n author: string;\n permlink: string;\n /** 40 hex chars when the broadcast path returned one; omitted otherwise. */\n trx_id?: string | null;\n ua_class: CurationUaClass;\n}\n\nexport type CurationDismissAction = \"dismiss\" | \"restore\";\n\nexport interface CurationDismissRecoInput {\n author: string;\n permlink: string;\n action: CurationDismissAction;\n}\n\nexport interface CurationDismissRecoResponse {\n row: CurationRosterRow;\n}\n"]}
1
+ {"version":3,"sources":["../../src/modules/curation/types.ts"],"names":["CURATION_REASONS","CURATION_SORTS","CURATION_VIEWS","CURATION_APPS","CURATION_WINDOWS","CURATION_MARK_STATES","CURATION_FLAG_REASONS"],"mappings":"AASO,IAAMA,CAAAA,CAAmB,CAAC,SAAA,CAAW,YAAA,CAAc,UAAA,CAAY,OAAO,CAAA,CAGhEC,CAAAA,CAAiB,CAAC,OAAA,CAAS,QAAA,CAAU,QAAA,CAAU,QAAQ,EAGvDC,CAAAA,CAAiB,CAC5B,OAAA,CACA,QAAA,CACA,aAAA,CACA,aAAA,CACA,SAAA,CACA,KAAA,CACA,UACF,CAAA,CAGaC,CAAAA,CAAgB,CAAC,KAAA,CAAO,QAAA,CAAU,QAAS,OAAO,CAAA,CAGlDC,CAAAA,CAAmB,CAAC,KAAA,CAAO,MAAA,CAAQ,MAAA,CAAQ,QAAA,CAAU,QAAA,CAAU,KAAK,CAAA,CAGpEC,CAAAA,CAAuB,CAAC,UAAA,CAAY,UAAW,SAAA,CAAW,OAAO,CAAA,CAGjEC,CAAAA,CAAwB,CACnC,YAAA,CACA,SAAA,CACA,UAAA,CACA,YAAA,CACA,WAAA,CACA,SAAA,CACA,eAAA,CACA,OACF","file":"chunk-ZLU6INZR.js","sourcesContent":["/**\n * Curation desk types.\n *\n * Shapes mirror the desk routes behind `/private-api/curation-desk/*`. Public\n * rows carry no curator identity; the roster feed and the tick add an `overlay`\n * with marks, signals and flags. The window state (full, half, eighth, locked,\n * paid) is never in a payload: clients derive it from `created` and `payout_at`.\n */\n\nexport const CURATION_REASONS = [\"quality\", \"underrated\", \"newcomer\", \"other\"] as const;\nexport type CurationReason = (typeof CURATION_REASONS)[number];\n\nexport const CURATION_SORTS = [\"queue\", \"newest\", \"unique\", \"random\"] as const;\nexport type CurationSort = (typeof CURATION_SORTS)[number];\n\nexport const CURATION_VIEWS = [\n \"queue\",\n \"latest\",\n \"new-authors\",\n \"recommended\",\n \"curated\",\n \"all\",\n \"excluded\",\n] as const;\nexport type CurationView = (typeof CURATION_VIEWS)[number];\n\nexport const CURATION_APPS = [\"all\", \"ecency\", \"peakd\", \"other\"] as const;\nexport type CurationApp = (typeof CURATION_APPS)[number];\n\nexport const CURATION_WINDOWS = [\"12h\", \"full\", \"half\", \"eighth\", \"locked\", \"all\"] as const;\nexport type CurationWindow = (typeof CURATION_WINDOWS)[number];\n\nexport const CURATION_MARK_STATES = [\"reviewed\", \"snoozed\", \"flagged\", \"noted\"] as const;\nexport type CurationMarkState = (typeof CURATION_MARK_STATES)[number];\n\nexport const CURATION_FLAG_REASONS = [\n \"plagiarism\",\n \"ai_slop\",\n \"recycled\",\n \"image_only\",\n \"tag_abuse\",\n \"farming\",\n \"nsfw_untagged\",\n \"other\",\n] as const;\nexport type CurationFlagReason = (typeof CURATION_FLAG_REASONS)[number];\n\nexport type CurationRole = \"admin\" | \"mod\" | \"curator\" | \"trial\";\n\n/** Filters shared by the public feed (query params) and the roster feed (body). */\nexport interface CurationFeedParams {\n sort?: CurationSort;\n view?: CurationView;\n app?: CurationApp;\n community?: string;\n window?: CurationWindow;\n rep_min?: number;\n rep_max?: number;\n min_words?: number;\n max_words?: number;\n has_images?: boolean;\n new_authors?: boolean;\n recommended?: boolean;\n hide_curated?: boolean;\n limit?: number;\n}\n\n/** Roster-only additions: the random seed and the team-mark predicates. */\nexport interface CurationRosterFeedParams extends CurationFeedParams {\n seed?: string;\n flagged?: boolean;\n hide_reviewed?: boolean;\n hide_snoozed?: boolean;\n}\n\nexport interface CurationTrailedBy {\n curator: string;\n at: string;\n weight: number;\n source: \"erobot_push\" | \"history\" | \"inferred\" | string;\n confirmed: boolean;\n}\n\nexport interface CurationVotedBy {\n voter: string;\n weight: number;\n at: string;\n}\n\n/** Public row (route 1, 4 rows are narrower, route 5 adds recommenders). */\nexport interface CurationRow {\n post_id: number;\n author: string;\n permlink: string;\n title: string;\n created: string;\n app: string | null;\n is_ecency: boolean;\n community: string | null;\n community_title: string | null;\n tags: string[];\n rep: number | null;\n is_new_author: boolean;\n author_post_count: number | null;\n author_created?: string | null;\n word_count: number | null;\n image_count: number;\n first_image: string | null;\n summary: string | null;\n edited_at: string | null;\n edit_count: number;\n votes: number | null;\n pending_payout: number | null;\n pending_payout_est?: number | null;\n payout_at: string | null;\n is_declined?: boolean | null;\n is_gray?: boolean | null;\n rshares_total?: number | null;\n rshares_after_24h?: number | null;\n /** 0 open, 1 curated, 2 dropped */\n state: number;\n trailed_by: CurationTrailedBy | null;\n voted_by: CurationVotedBy[];\n author_trailed_at: string | null;\n /** Set on the hivewatchers unvote path. */\n unvoted_at?: string | null;\n /** Materialization time; with `created` it tells a late row. */\n inserted_at?: string | null;\n recommend_count: number;\n unique_recommenders: number;\n reco_no_meta_count: number;\n /** Opaque keyset cursor for the page that follows this row. */\n _cursor?: string;\n}\n\nexport interface CurationMark {\n curator: string;\n state: CurationMarkState;\n reason?: string | null;\n note?: string | null;\n /**\n * Whether a note body exists. Tick deltas carry this instead of the body,\n * so a delta must never overwrite a note the client already holds.\n */\n has_note?: boolean;\n snooze_until?: string | null;\n updated_at: string;\n}\n\nexport interface CurationSignals {\n /** Whole percents (0-100) as the signals service sends them, never a 0-1 fraction. */\n formulaic?: number | null;\n images?: { hive_hosted?: number; external?: number; total?: number } | null;\n engagement?: { replies_per_day?: number | null } | null;\n /** `n` is how many of the author's own past posts the baseline holds, `driver` the feature that moved most. */\n style?: { alert?: boolean; sigma?: number | null; driver?: string; n?: number } | null;\n /**\n * The detector's read of the post's FIRST image, which is the one rendered as the\n * thumbnail. `over` is the only field to act on; `score` and `classes` are for tuning.\n * A null score means unknown (no image, or the check could not run), never \"clean\".\n */\n nsfw?: {\n score?: number | null;\n class?: string | null;\n over?: boolean;\n classes?: string[];\n note?: string;\n } | null;\n [key: string]: unknown;\n}\n\nexport interface CurationFlags {\n low_rep?: boolean;\n /** The author's reputation has gone negative, which is not the same line as low_rep. */\n negative_rep?: boolean;\n ignorelist?: boolean;\n abuser?: boolean;\n spaminator?: boolean;\n blocked_tag?: boolean;\n /** The post carries Hive's own `nsfw` tag. */\n nsfw?: boolean;\n patch_body?: boolean;\n deleted?: boolean;\n hivewatchers_downvote?: boolean;\n [key: string]: unknown;\n}\n\n/** Roster-only overlay shipped inline with the roster feed and in tick deltas. */\nexport interface CurationOverlay {\n signals: CurationSignals | null;\n flags: CurationFlags;\n excluded_reason: string | null;\n team_mark: CurationMarkState | null;\n team_mark_by: string | null;\n team_snooze_until?: string | null;\n resurfaced_at: string | null;\n /** Set when the roster dismissed the recommendations of this post. */\n reco_dismissed_at?: string | null;\n marks: CurationMark[];\n notes_count: number;\n}\n\nexport type CurationRosterRow = CurationRow & { overlay: CurationOverlay | null };\n\nexport interface CurationTeamCursor {\n post_id: number | null;\n created: string | null;\n set_by?: string;\n set_at?: string;\n}\n\nexport interface CurationActiveCurator {\n username: string;\n last_action_at: string;\n}\n\n/**\n * The narrowing facets a curator was working when they made a mark. Empty means\n * the whole queue. The keys are the roster feed's own params, so a value here has\n * already been through the allow lists the query runs on.\n */\nexport type CurationLane = Partial<{\n /** Present only when it is not the queue order, under which alone a position is a watermark. */\n sort: CurationSort;\n view: string;\n app: CurationApp;\n community: string;\n window: CurationWindow;\n rep_min: number;\n rep_max: number;\n min_words: number;\n max_words: number;\n has_images: boolean;\n new_authors: boolean;\n recommended: boolean;\n flagged: boolean;\n hide_curated: boolean;\n hide_reviewed: boolean;\n hide_snoozed: boolean;\n}>;\n\n/**\n * How far one curator has got, derived from their marks so nobody types it. This\n * is the hand-off curators used to post in Discord.\n *\n * `reviewed_to` is a progress claim rather than a contiguous reviewed prefix: a\n * mark is any of the four states and marks are not made in queue order. It is\n * read, never used to aim anything. `lane` travels with the mark that set the\n * position, so the two always describe the same moment. Roster-only: the public\n * payloads carry no per-curator activity at all.\n */\nexport interface CurationHandoffEntry {\n username: string;\n reviewed_to: string | null;\n reviewed_to_post_id: number | null;\n last_mark_at: string;\n /** Absent for a trial viewer looking at somebody else. */\n marks_24h?: number;\n /**\n * Null is UNKNOWN: a mark from before the desk sent lanes, or one that said\n * nothing. It is never the whole queue, which is `{}`. Absent until the\n * backend that records it is deployed.\n */\n lane?: CurationLane | null;\n}\n\nexport interface CurationFeedPage {\n items: CurationRow[];\n next_cursor: string | null;\n team_cursor: CurationTeamCursor;\n head_lag_seconds: number;\n feed_version: string | null;\n generated_at: string;\n}\n\nexport interface CurationRosterFeedPage {\n items: CurationRosterRow[];\n next_cursor: string | null;\n team_cursor: CurationTeamCursor;\n active_curators: CurationActiveCurator[];\n /** Roster only, and absent until the backend that derives it is deployed. */\n handoff?: CurationHandoffEntry[];\n facets: { communities: Array<{ community: string; title?: string | null; count?: number }> };\n total_estimate: number | null;\n head_lag_seconds: number;\n generated_at: string;\n}\n\nexport interface CurationManaSpent {\n equiv: number;\n trail: number;\n other: number;\n crosscheck: number | null;\n since: string;\n}\n\nexport interface CurationVp {\n account: string;\n percent: number;\n live_percent: number;\n implied_weight: number;\n at: string;\n sustainable_votes_per_day: number;\n regen_votes_per_hour: number;\n reward_fund?: {\n recent_claims: string | number;\n reward_balance: number;\n median_price: number;\n at: string;\n } | null;\n}\n\nexport interface CurationStatus {\n team_cursor: CurationTeamCursor;\n behind_seconds: number | null;\n counts: {\n unreviewed: number;\n curated_24h: number;\n trail_votes_today: { posts: number; comments: number };\n recommended_posts: number;\n };\n /**\n * The application window, carried on status so no page needs a second call to\n * find out whether it may invite anyone. Older desks do not send it.\n */\n applications?: CurationApplicationWindow;\n mana_spent_today: CurationManaSpent | null;\n vp: CurationVp | null;\n head_lag_seconds: number;\n reco_lag_blocks: number | null;\n feed_version: string | null;\n latest_post_id: number | null;\n worker_tick_age_seconds: number | null;\n}\n\n/**\n * The per-curator conditions erobot applies before trailing a vote. The three\n * weights are Hive vote weights (100 = 1%); `trail` overrides the per-role\n * default, and is what `config.followAccounts` used to be.\n */\nexport interface CurationRosterRules {\n min_weight?: number;\n max_weight?: number;\n waves_only_below?: number;\n trail?: boolean;\n}\n\nexport interface CurationRosterEntry {\n username: string;\n role: CurationRole;\n active: boolean;\n rules?: CurationRosterRules | null;\n /** Resolved by the backend, so no client re-implements the per-role default. */\n trail?: boolean;\n}\n\n/**\n * The admin view of a row. These fields are private, so they arrive from the\n * roster-list POST and never from the edge-cached roster GET.\n */\nexport interface CurationRosterAdminEntry extends CurationRosterEntry {\n added_by: string | null;\n added_at: string | null;\n removed_at: string | null;\n note: string | null;\n /** When a guest seat runs out. Null means permanent, which every hand-set seat is. */\n term_ends?: string | null;\n}\n\nexport interface CurationRoster {\n curators: CurationRosterEntry[];\n updated_at: string;\n}\n\nexport interface CurationRosterAdminList {\n curators: CurationRosterAdminEntry[];\n}\n\n/** Open or closed, with the line shown to a reader while it is closed. */\nexport interface CurationApplicationWindow {\n open: boolean;\n message: string | null;\n /** Only the admin routes return this; status carries the two fields above. */\n updated_at?: string | null;\n}\n\nexport type CurationApplicationState =\n | \"open\"\n | \"shortlisted\"\n | \"accepted\"\n | \"declined\"\n | \"withdrawn\";\n\n/** The three questions the apply form asks, as the desk stores them. */\nexport interface CurationApplicationAnswers {\n motivation: string;\n availability: string;\n pick: string;\n}\n\n/** What an applicant sees of their own application. */\nexport interface CurationApplication {\n id: number;\n username: string;\n answers: CurationApplicationAnswers;\n state: CurationApplicationState;\n created: string;\n updated_at: string;\n decided_at: string | null;\n}\n\n/**\n * How a reviewer answered. An objection stops the automatic grant; it never declines,\n * and `abstain` is how a stop is lifted without turning into a vote in favour.\n */\nexport type CurationApplicationVoteValue = \"endorse\" | \"object\" | \"abstain\";\n\n/** One reviewer's line on one application. Private to the review queue. */\nexport interface CurationApplicationVote {\n voter: string;\n vote: CurationApplicationVoteValue;\n note: string | null;\n created: string;\n updated_at: string;\n /**\n * Whether that voter is still on the bench. A vote from somebody since retired or\n * demoted stops counting toward the quorum, and the desk sends the line anyway so a\n * total one short has a visible reason.\n */\n standing: boolean;\n}\n\nexport interface CurationApplicationTally {\n endorsed: number;\n objected: number;\n}\n\n/**\n * The reviewer's view. `snapshot` is the applicant's recommendation record as it\n * stood when they applied, frozen because the live record keeps moving.\n */\nexport interface CurationApplicationAdminEntry extends CurationApplication {\n snapshot: CurationRecommenderStats | null;\n decided_by: string | null;\n admin_note: string | null;\n}\n\n/**\n * A row as the review QUEUE sends it: the reviewer's view plus the bench's votes on it.\n * Separate from the entry above because only the queue carries these three. The desk's\n * vote response returns the plain admin entry with the votes beside it, not inside it,\n * so a single type covering both would let a caller dereference fields that are not there.\n */\nexport interface CurationApplicationQueueEntry extends CurationApplicationAdminEntry {\n votes: CurationApplicationVote[];\n tally: CurationApplicationTally;\n /** This viewer's own line, so the queue does not walk the list to find it. */\n my_vote: CurationApplicationVoteValue | null;\n}\n\nexport interface CurationApplicationMine {\n application: CurationApplication | null;\n window: CurationApplicationWindow;\n /** The viewer's roster role, so the page can say \"you are already a curator\". */\n role: CurationRole | null;\n}\n\nexport interface CurationApplicationList {\n applications: CurationApplicationQueueEntry[];\n counts: Partial<Record<CurationApplicationState, number>>;\n window: CurationApplicationWindow;\n /** Endorsements that grant a seat, and how long that seat lasts. Never public. */\n quorum: number;\n term_days: number;\n}\n\nexport interface CurationApplicationVoteInput {\n applicant: string;\n vote: CurationApplicationVoteValue;\n note?: string;\n}\n\nexport interface CurationApplicationVoteResult {\n /** The plain admin entry. The votes and the tally are beside it, not inside it. */\n application: CurationApplicationAdminEntry;\n votes: CurationApplicationVote[];\n tally: CurationApplicationTally;\n quorum: number;\n /** True when this vote reached the quorum and the seat was granted. */\n elected: boolean;\n}\n\nexport interface CurationApplicationDecideInput {\n applicant: string;\n /** Only the three a reviewer may set; `open` and `withdrawn` are not decisions. */\n state: \"shortlisted\" | \"accepted\" | \"declined\";\n /** Accepting only. Defaults to `curator` upstream, which IS trailed, with a term. */\n role?: Extract<CurationRole, \"curator\" | \"mod\">;\n note?: string;\n}\n\nexport interface CurationRosterSetInput {\n curator: string;\n role: CurationRole;\n rules?: CurationRosterRules;\n note?: string;\n /**\n * Tri-state upstream: leave it out to KEEP the seat's term, 0 to make the seat\n * permanent, n to restart the clock. Leaving it out is deliberately not \"make\n * permanent\", so editing a note cannot quietly turn a guest seat into a standing one.\n */\n term_days?: number;\n}\n\nexport interface CurationRecommender {\n username: string;\n rep: number | null;\n reason: CurationReason | null;\n at: string;\n has_meta: boolean;\n is_self?: boolean;\n /**\n * Ordering weight of this recommender, 0.5 to 1.5 with 1.0 neutral. Above\n * 1.0 means curators curated their picks more often than they dismissed\n * them over the window. It changes ordering only, never what is shown.\n */\n precision?: number;\n /** At least 10 recommendations and a precision of 1.2 or more. */\n trusted?: boolean;\n}\n\n/**\n * Route 14: one recommender's 90-day scorecard. An unknown username answers\n * zeros with a neutral precision and `trusted: false`, never a 404, so a name\n * that never recommended anything is not an error state.\n */\nexport interface CurationRecommenderStats {\n username: string;\n window_days: number;\n recommended: number;\n curated: number;\n dismissed: number;\n withdrawn: number;\n precision: number;\n trusted: boolean;\n computed_at: string | null;\n}\n\nexport type CurationReasonsHistogram = Partial<Record<CurationReason, number>>;\n\nexport interface CurationRecommendationItem {\n author: string;\n permlink: string;\n title: string;\n created: string;\n /**\n * The post's cover, the same column the feed row carries. Optional because a\n * desk older than the field answers without it; absent and null both mean no\n * cover, and the caller proxifies before rendering.\n */\n first_image?: string | null;\n recommend_count: number;\n unique_recommenders: number;\n no_meta_count: number;\n reasons: CurationReasonsHistogram;\n recommenders: CurationRecommender[];\n _cursor?: string;\n}\n\nexport interface CurationRecommendationsPage {\n items: CurationRecommendationItem[];\n next_cursor: string | null;\n}\n\nexport type CurationRecommendationsSort = \"unique\" | \"newest\";\n\nexport interface CurationRecommendationsParams {\n sort?: CurationRecommendationsSort;\n limit?: number;\n}\n\n/** Route 5: the public row plus the recommender list, self row included. */\nexport interface CurationPost extends CurationRow {\n recommenders: CurationRecommender[];\n no_meta_count: number;\n reasons: CurationReasonsHistogram;\n}\n\nexport interface CurationTickRequest {\n /** `generated_at` echoed verbatim from the previous response. */\n since: string | null;\n /** Loaded rows that have no overlay yet (at most 100). */\n need: number[];\n /** Visible rows (at most 100). */\n visible: number[];\n}\n\n/**\n * Tick answer. `truncated` says the delta window was too wide to answer in\n * full; it only means something when the request carried a `since`, since a\n * first tick with `since: null` asks for a snapshot, not a window.\n */\nexport interface CurationTickResponse {\n overlay: Array<{ post_id: number } & CurationOverlay>;\n deltas: {\n marks: Array<{ post_id: number } & CurationMark>;\n flags: Array<{ post_id: number; flags: CurationFlags; excluded_reason: string | null }>;\n signals: Array<{ post_id: number; signals: CurationSignals | null }>;\n /**\n * Rows whose curation state moved since the client's own `generated_at`.\n * The overlay carries no state, so without these a page the client keeps\n * holding would render a curated post as open and votable. Optional: a\n * backend that predates it simply sends nothing.\n */\n rows?: Array<\n Pick<CurationRow, \"post_id\" | \"state\" | \"trailed_by\" | \"voted_by\" | \"unvoted_at\">\n >;\n };\n team_cursor: CurationTeamCursor;\n active_curators: CurationActiveCurator[];\n /** Roster only, and absent until the backend that derives it is deployed. */\n handoff?: CurationHandoffEntry[];\n trail_alerts: unknown[];\n generated_at: string;\n truncated: boolean;\n}\n\nexport interface CurationMarkInput {\n author: string;\n permlink: string;\n state: CurationMarkState;\n reason?: string;\n note?: string;\n snooze_until?: string;\n /**\n * The feed params the desk was showing when it made this mark. The hand-off\n * reads a position and its lane off the same mark, so a desk with two tabs on\n * different filters stamps each mark with its own. Paging keys are dropped by\n * the gateway; absent means the lane is unknown, never the whole queue.\n */\n lane?: CurationRosterFeedParams;\n}\n\nexport interface CurationMarkResponse {\n mark: CurationMark | null;\n row: CurationRosterRow;\n}\n\nexport interface CurationMarkClearResponse {\n ok: boolean;\n row: CurationRosterRow;\n}\n\nexport interface CurationMyMarksParams {\n state?: CurationMarkState;\n cursor?: string;\n limit?: number;\n}\n\nexport interface CurationMyMark extends CurationMark {\n post_id: number;\n author: string;\n permlink: string;\n title: string;\n created: string;\n row?: CurationRosterRow | null;\n}\n\nexport interface CurationMyMarksResponse {\n items: CurationMyMark[];\n next_cursor: string | null;\n}\n\nexport type CurationCursorAction = \"advance\" | \"rewind\";\n\nexport interface CurationCursorInput {\n post_id: number;\n action: CurationCursorAction;\n reason?: string;\n}\n\nexport interface CurationCursorResponse {\n team_cursor: CurationTeamCursor;\n moved: boolean;\n swept_count: number | null;\n}\n\nexport type CurationUaClass = \"web\" | \"mobile\";\n\nexport interface CurationRecommendMetaInput {\n author: string;\n permlink: string;\n /** 40 hex chars when the broadcast path returned one; omitted otherwise. */\n trx_id?: string | null;\n ua_class: CurationUaClass;\n}\n\nexport type CurationDismissAction = \"dismiss\" | \"restore\";\n\nexport interface CurationDismissRecoInput {\n author: string;\n permlink: string;\n action: CurationDismissAction;\n}\n\nexport interface CurationDismissRecoResponse {\n row: CurationRosterRow;\n}\n"]}