aimeat 2.4.0 → 2.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (308) hide show
  1. package/dist/.env.example +33 -0
  2. package/dist/build-stamp.json +13 -0
  3. package/dist/locales/en.json +186 -20
  4. package/dist/locales/fi.json +186 -20
  5. package/dist/public/components/VoiceRecorder.js +116 -0
  6. package/dist/public/connection-done.html +53 -0
  7. package/dist/public/css/components/voice-recorder.css +66 -0
  8. package/dist/public/css/views/inbox.css +41 -0
  9. package/dist/public/css/views/profile.css +171 -95
  10. package/dist/public/css/views/transparency.css +5 -0
  11. package/dist/public/js/services/audio-recorder.js +171 -0
  12. package/dist/public/js/services/messages.js +21 -2
  13. package/dist/public/spa.html +3 -0
  14. package/dist/public/views/landing.js +4 -0
  15. package/dist/public/views/profile/access-tab/connections.js +264 -0
  16. package/dist/public/views/profile/access-tab.js +2 -0
  17. package/dist/public/views/profile/ai-transparency-card.js +22 -17
  18. package/dist/public/views/profile/inbox-tab/components.js +60 -10
  19. package/dist/public/views/profile/inbox-tab/helpers.js +33 -0
  20. package/dist/public/views/profile/inbox-tab/panels.js +6 -1
  21. package/dist/public/views/profile/inbox-tab/use-voice.js +50 -0
  22. package/dist/public/views/profile/inbox-tab/voice-parts.js +111 -0
  23. package/dist/public/views/profile/inbox-tab.js +18 -24
  24. package/dist/public/views/profile/openrouter/budget-panel.js +224 -0
  25. package/dist/public/views/profile/openrouter/model-picker.js +150 -0
  26. package/dist/public/views/profile/openrouter/pricing.js +139 -0
  27. package/dist/public/views/profile/openrouter-settings.js +425 -488
  28. package/dist/public/views/transparency.js +50 -0
  29. package/dist/scripts/build-sdk-libs.d.ts.map +1 -1
  30. package/dist/scripts/build-sdk-libs.js +1 -0
  31. package/dist/scripts/build-sdk-libs.js.map +1 -1
  32. package/dist/scripts/check-ai-disclosure.d.ts.map +1 -1
  33. package/dist/scripts/check-ai-disclosure.js +182 -0
  34. package/dist/scripts/check-ai-disclosure.js.map +1 -1
  35. package/dist/src/cli/connect/ai-provenance-carry.d.ts +247 -0
  36. package/dist/src/cli/connect/ai-provenance-carry.d.ts.map +1 -0
  37. package/dist/src/cli/connect/ai-provenance-carry.js +334 -0
  38. package/dist/src/cli/connect/ai-provenance-carry.js.map +1 -0
  39. package/dist/src/cli/connect/api-client.d.ts +11 -0
  40. package/dist/src/cli/connect/api-client.d.ts.map +1 -1
  41. package/dist/src/cli/connect/api-client.js +2 -0
  42. package/dist/src/cli/connect/api-client.js.map +1 -1
  43. package/dist/src/cli/connect/mcp/local-server.d.ts.map +1 -1
  44. package/dist/src/cli/connect/mcp/local-server.js +11 -0
  45. package/dist/src/cli/connect/mcp/local-server.js.map +1 -1
  46. package/dist/src/cli/connect/mcp/tools/agent-messages.d.ts +2 -0
  47. package/dist/src/cli/connect/mcp/tools/agent-messages.d.ts.map +1 -1
  48. package/dist/src/cli/connect/mcp/tools/agent-messages.js +5 -2
  49. package/dist/src/cli/connect/mcp/tools/agent-messages.js.map +1 -1
  50. package/dist/src/cli/connect/mcp/tools/agent-tasks.d.ts +2 -0
  51. package/dist/src/cli/connect/mcp/tools/agent-tasks.d.ts.map +1 -1
  52. package/dist/src/cli/connect/mcp/tools/agent-tasks.js +5 -2
  53. package/dist/src/cli/connect/mcp/tools/agent-tasks.js.map +1 -1
  54. package/dist/src/cli/connect/mcp/tools/apps.d.ts +3 -0
  55. package/dist/src/cli/connect/mcp/tools/apps.d.ts.map +1 -1
  56. package/dist/src/cli/connect/mcp/tools/apps.js +13 -5
  57. package/dist/src/cli/connect/mcp/tools/apps.js.map +1 -1
  58. package/dist/src/cli/connect/mcp/tools/boards.d.ts +3 -0
  59. package/dist/src/cli/connect/mcp/tools/boards.d.ts.map +1 -1
  60. package/dist/src/cli/connect/mcp/tools/boards.js +5 -2
  61. package/dist/src/cli/connect/mcp/tools/boards.js.map +1 -1
  62. package/dist/src/cli/connect/mcp/tools/core.d.ts +5 -0
  63. package/dist/src/cli/connect/mcp/tools/core.d.ts.map +1 -1
  64. package/dist/src/cli/connect/mcp/tools/core.js +25 -5
  65. package/dist/src/cli/connect/mcp/tools/core.js.map +1 -1
  66. package/dist/src/cli/connect/mcp/tools/dm-messages.d.ts +2 -0
  67. package/dist/src/cli/connect/mcp/tools/dm-messages.d.ts.map +1 -1
  68. package/dist/src/cli/connect/mcp/tools/dm-messages.js +11 -6
  69. package/dist/src/cli/connect/mcp/tools/dm-messages.js.map +1 -1
  70. package/dist/src/cli/connect/mcp/tools/exchange.d.ts +2 -0
  71. package/dist/src/cli/connect/mcp/tools/exchange.d.ts.map +1 -1
  72. package/dist/src/cli/connect/mcp/tools/exchange.js +8 -2
  73. package/dist/src/cli/connect/mcp/tools/exchange.js.map +1 -1
  74. package/dist/src/cli/connect/mcp/tools/knowledge.d.ts +3 -0
  75. package/dist/src/cli/connect/mcp/tools/knowledge.d.ts.map +1 -1
  76. package/dist/src/cli/connect/mcp/tools/knowledge.js +7 -3
  77. package/dist/src/cli/connect/mcp/tools/knowledge.js.map +1 -1
  78. package/dist/src/cli/connect/mcp/tools/organisms.d.ts +2 -0
  79. package/dist/src/cli/connect/mcp/tools/organisms.d.ts.map +1 -1
  80. package/dist/src/cli/connect/mcp/tools/organisms.js +7 -2
  81. package/dist/src/cli/connect/mcp/tools/organisms.js.map +1 -1
  82. package/dist/src/cli/connect/mcp/tools/workspaces.d.ts +3 -0
  83. package/dist/src/cli/connect/mcp/tools/workspaces.d.ts.map +1 -1
  84. package/dist/src/cli/connect/mcp/tools/workspaces.js +8 -2
  85. package/dist/src/cli/connect/mcp/tools/workspaces.js.map +1 -1
  86. package/dist/src/cli/connect/tool-call-defs-core.d.ts +3 -0
  87. package/dist/src/cli/connect/tool-call-defs-core.d.ts.map +1 -1
  88. package/dist/src/cli/connect/tool-call-defs-core.js +7 -0
  89. package/dist/src/cli/connect/tool-call-defs-core.js.map +1 -1
  90. package/dist/src/cli/connect/tool-call.d.ts +3 -0
  91. package/dist/src/cli/connect/tool-call.d.ts.map +1 -1
  92. package/dist/src/cli/connect/tool-call.js +11 -1
  93. package/dist/src/cli/connect/tool-call.js.map +1 -1
  94. package/dist/src/config-types.d.ts +14 -0
  95. package/dist/src/config-types.d.ts.map +1 -1
  96. package/dist/src/config.d.ts.map +1 -1
  97. package/dist/src/config.js +10 -0
  98. package/dist/src/config.js.map +1 -1
  99. package/dist/src/data/public-pages.d.ts +12 -0
  100. package/dist/src/data/public-pages.d.ts.map +1 -1
  101. package/dist/src/data/public-pages.js +12 -0
  102. package/dist/src/data/public-pages.js.map +1 -1
  103. package/dist/src/generated/api-types.d.ts +969 -85
  104. package/dist/src/generated/api-types.d.ts.map +1 -1
  105. package/dist/src/mcp/ai-provenance-input.d.ts +45 -2
  106. package/dist/src/mcp/ai-provenance-input.d.ts.map +1 -1
  107. package/dist/src/mcp/ai-provenance-input.js +48 -2
  108. package/dist/src/mcp/ai-provenance-input.js.map +1 -1
  109. package/dist/src/mcp/apps.d.ts +7 -0
  110. package/dist/src/mcp/apps.d.ts.map +1 -1
  111. package/dist/src/mcp/apps.js +20 -2
  112. package/dist/src/mcp/apps.js.map +1 -1
  113. package/dist/src/models/ai-provenance-schemas.d.ts +7 -1
  114. package/dist/src/models/ai-provenance-schemas.d.ts.map +1 -1
  115. package/dist/src/models/ai-provenance-schemas.js +11 -1
  116. package/dist/src/models/ai-provenance-schemas.js.map +1 -1
  117. package/dist/src/models/connection-schemas.d.ts +203 -0
  118. package/dist/src/models/connection-schemas.d.ts.map +1 -0
  119. package/dist/src/models/connection-schemas.js +33 -0
  120. package/dist/src/models/connection-schemas.js.map +1 -0
  121. package/dist/src/models/message-schemas.d.ts +40 -0
  122. package/dist/src/models/message-schemas.d.ts.map +1 -1
  123. package/dist/src/models/message-schemas.js +23 -0
  124. package/dist/src/models/message-schemas.js.map +1 -1
  125. package/dist/src/routes/ai-provenance.d.ts +6 -0
  126. package/dist/src/routes/ai-provenance.d.ts.map +1 -1
  127. package/dist/src/routes/ai-provenance.js +34 -1
  128. package/dist/src/routes/ai-provenance.js.map +1 -1
  129. package/dist/src/routes/ai-transparency.d.ts +6 -1
  130. package/dist/src/routes/ai-transparency.d.ts.map +1 -1
  131. package/dist/src/routes/ai-transparency.js +17 -3
  132. package/dist/src/routes/ai-transparency.js.map +1 -1
  133. package/dist/src/routes/ai.d.ts +5 -0
  134. package/dist/src/routes/ai.d.ts.map +1 -1
  135. package/dist/src/routes/ai.js +83 -0
  136. package/dist/src/routes/ai.js.map +1 -1
  137. package/dist/src/routes/app-grants.d.ts.map +1 -1
  138. package/dist/src/routes/app-grants.js +4 -0
  139. package/dist/src/routes/app-grants.js.map +1 -1
  140. package/dist/src/routes/apps/drafts.d.ts +3 -0
  141. package/dist/src/routes/apps/drafts.d.ts.map +1 -1
  142. package/dist/src/routes/apps/drafts.js +13 -0
  143. package/dist/src/routes/apps/drafts.js.map +1 -1
  144. package/dist/src/routes/apps/publish.d.ts +5 -0
  145. package/dist/src/routes/apps/publish.d.ts.map +1 -1
  146. package/dist/src/routes/apps/publish.js +21 -5
  147. package/dist/src/routes/apps/publish.js.map +1 -1
  148. package/dist/src/routes/connections.d.ts +35 -0
  149. package/dist/src/routes/connections.d.ts.map +1 -0
  150. package/dist/src/routes/connections.js +406 -0
  151. package/dist/src/routes/connections.js.map +1 -0
  152. package/dist/src/routes/libs.js +1 -1
  153. package/dist/src/routes/libs.js.map +1 -1
  154. package/dist/src/routes/messages.d.ts +5 -0
  155. package/dist/src/routes/messages.d.ts.map +1 -1
  156. package/dist/src/routes/messages.js +92 -0
  157. package/dist/src/routes/messages.js.map +1 -1
  158. package/dist/src/routes/openrouter.d.ts +6 -1
  159. package/dist/src/routes/openrouter.d.ts.map +1 -1
  160. package/dist/src/routes/openrouter.js +37 -7
  161. package/dist/src/routes/openrouter.js.map +1 -1
  162. package/dist/src/routes/upload.d.ts +5 -0
  163. package/dist/src/routes/upload.d.ts.map +1 -1
  164. package/dist/src/routes/upload.js +32 -0
  165. package/dist/src/routes/upload.js.map +1 -1
  166. package/dist/src/server-bootstrap/routes-loader.d.ts.map +1 -1
  167. package/dist/src/server-bootstrap/routes-loader.js +2 -0
  168. package/dist/src/server-bootstrap/routes-loader.js.map +1 -1
  169. package/dist/src/services/ai-completion.d.ts +48 -0
  170. package/dist/src/services/ai-completion.d.ts.map +1 -1
  171. package/dist/src/services/ai-completion.js +112 -72
  172. package/dist/src/services/ai-completion.js.map +1 -1
  173. package/dist/src/services/ai-disclosure.d.ts +6 -0
  174. package/dist/src/services/ai-disclosure.d.ts.map +1 -1
  175. package/dist/src/services/ai-disclosure.js +20 -2
  176. package/dist/src/services/ai-disclosure.js.map +1 -1
  177. package/dist/src/services/ai-provenance-page.d.ts +59 -0
  178. package/dist/src/services/ai-provenance-page.d.ts.map +1 -0
  179. package/dist/src/services/ai-provenance-page.js +185 -0
  180. package/dist/src/services/ai-provenance-page.js.map +1 -0
  181. package/dist/src/services/ai-provenance.d.ts +6 -0
  182. package/dist/src/services/ai-provenance.d.ts.map +1 -1
  183. package/dist/src/services/ai-provenance.js +5 -0
  184. package/dist/src/services/ai-provenance.js.map +1 -1
  185. package/dist/src/services/ai-transcription.d.ts +66 -0
  186. package/dist/src/services/ai-transcription.d.ts.map +1 -0
  187. package/dist/src/services/ai-transcription.js +90 -0
  188. package/dist/src/services/ai-transcription.js.map +1 -0
  189. package/dist/src/services/app-publish.d.ts.map +1 -1
  190. package/dist/src/services/app-publish.js +16 -1
  191. package/dist/src/services/app-publish.js.map +1 -1
  192. package/dist/src/services/build-app-prompt.d.ts.map +1 -1
  193. package/dist/src/services/build-app-prompt.js +2 -1
  194. package/dist/src/services/build-app-prompt.js.map +1 -1
  195. package/dist/src/services/connections/attach.d.ts +62 -0
  196. package/dist/src/services/connections/attach.d.ts.map +1 -0
  197. package/dist/src/services/connections/attach.js +168 -0
  198. package/dist/src/services/connections/attach.js.map +1 -0
  199. package/dist/src/services/connections/credential.d.ts +39 -0
  200. package/dist/src/services/connections/credential.d.ts.map +1 -0
  201. package/dist/src/services/connections/credential.js +66 -0
  202. package/dist/src/services/connections/credential.js.map +1 -0
  203. package/dist/src/services/connections/instance.d.ts +65 -0
  204. package/dist/src/services/connections/instance.d.ts.map +1 -0
  205. package/dist/src/services/connections/instance.js +144 -0
  206. package/dist/src/services/connections/instance.js.map +1 -0
  207. package/dist/src/services/connections/oauth.d.ts +77 -0
  208. package/dist/src/services/connections/oauth.d.ts.map +1 -0
  209. package/dist/src/services/connections/oauth.js +290 -0
  210. package/dist/src/services/connections/oauth.js.map +1 -0
  211. package/dist/src/services/connections/providers.d.ts +118 -0
  212. package/dist/src/services/connections/providers.d.ts.map +1 -0
  213. package/dist/src/services/connections/providers.js +260 -0
  214. package/dist/src/services/connections/providers.js.map +1 -0
  215. package/dist/src/services/connections/publish-gate.d.ts +103 -0
  216. package/dist/src/services/connections/publish-gate.d.ts.map +1 -0
  217. package/dist/src/services/connections/publish-gate.js +0 -0
  218. package/dist/src/services/connections/publish-gate.js.map +1 -0
  219. package/dist/src/services/connections/publish.d.ts +60 -0
  220. package/dist/src/services/connections/publish.d.ts.map +1 -0
  221. package/dist/src/services/connections/publish.js +340 -0
  222. package/dist/src/services/connections/publish.js.map +1 -0
  223. package/dist/src/services/connections/refresh.d.ts +55 -0
  224. package/dist/src/services/connections/refresh.d.ts.map +1 -0
  225. package/dist/src/services/connections/refresh.js +307 -0
  226. package/dist/src/services/connections/refresh.js.map +1 -0
  227. package/dist/src/services/markdown-negotiation.d.ts +17 -0
  228. package/dist/src/services/markdown-negotiation.d.ts.map +1 -1
  229. package/dist/src/services/markdown-negotiation.js +15 -0
  230. package/dist/src/services/markdown-negotiation.js.map +1 -1
  231. package/dist/src/services/message-send.d.ts.map +1 -1
  232. package/dist/src/services/message-send.js +16 -2
  233. package/dist/src/services/message-send.js.map +1 -1
  234. package/dist/src/services/openrouter.d.ts +67 -1
  235. package/dist/src/services/openrouter.d.ts.map +1 -1
  236. package/dist/src/services/openrouter.js +102 -11
  237. package/dist/src/services/openrouter.js.map +1 -1
  238. package/dist/src/services/upload-token.d.ts +5 -1
  239. package/dist/src/services/upload-token.d.ts.map +1 -1
  240. package/dist/src/services/upload-token.js +13 -1
  241. package/dist/src/services/upload-token.js.map +1 -1
  242. package/dist/src/services/workflow/engine-util.d.ts +18 -0
  243. package/dist/src/services/workflow/engine-util.d.ts.map +1 -1
  244. package/dist/src/services/workflow/engine-util.js +27 -0
  245. package/dist/src/services/workflow/engine-util.js.map +1 -1
  246. package/dist/src/services/workflow/engine.d.ts.map +1 -1
  247. package/dist/src/services/workflow/engine.js +4 -2
  248. package/dist/src/services/workflow/engine.js.map +1 -1
  249. package/dist/src/storage/interface.d.ts +2 -1
  250. package/dist/src/storage/interface.d.ts.map +1 -1
  251. package/dist/src/storage/providers/postgres-kysely/db-types.d.ts +65 -0
  252. package/dist/src/storage/providers/postgres-kysely/db-types.d.ts.map +1 -1
  253. package/dist/src/storage/providers/postgres-kysely/index.d.ts.map +1 -1
  254. package/dist/src/storage/providers/postgres-kysely/index.js +2 -1
  255. package/dist/src/storage/providers/postgres-kysely/index.js.map +1 -1
  256. package/dist/src/storage/providers/postgres-kysely/methods/connections.d.ts +44 -0
  257. package/dist/src/storage/providers/postgres-kysely/methods/connections.d.ts.map +1 -0
  258. package/dist/src/storage/providers/postgres-kysely/methods/connections.js +308 -0
  259. package/dist/src/storage/providers/postgres-kysely/methods/connections.js.map +1 -0
  260. package/dist/src/storage/providers/postgres-kysely/methods/node-infra.d.ts.map +1 -1
  261. package/dist/src/storage/providers/postgres-kysely/methods/node-infra.js +4 -2
  262. package/dist/src/storage/providers/postgres-kysely/methods/node-infra.js.map +1 -1
  263. package/dist/src/storage/providers/postgres-kysely/migrations/0021_connections.sql +116 -0
  264. package/dist/src/storage/providers/postgres-kysely/migrations/0022_provider_clients.sql +36 -0
  265. package/dist/src/storage/providers/postgres-kysely/migrations/0023_nonce_payload.sql +13 -0
  266. package/dist/src/storage/providers/sqlite/index.d.ts.map +1 -1
  267. package/dist/src/storage/providers/sqlite/index.js +2 -1
  268. package/dist/src/storage/providers/sqlite/index.js.map +1 -1
  269. package/dist/src/storage/providers/sqlite/methods/community.d.ts.map +1 -1
  270. package/dist/src/storage/providers/sqlite/methods/community.js +2 -1
  271. package/dist/src/storage/providers/sqlite/methods/community.js.map +1 -1
  272. package/dist/src/storage/providers/sqlite/methods/connections.d.ts +60 -0
  273. package/dist/src/storage/providers/sqlite/methods/connections.d.ts.map +1 -0
  274. package/dist/src/storage/providers/sqlite/methods/connections.js +287 -0
  275. package/dist/src/storage/providers/sqlite/methods/connections.js.map +1 -0
  276. package/dist/src/storage/providers/sqlite/schema-tables-1.d.ts.map +1 -1
  277. package/dist/src/storage/providers/sqlite/schema-tables-1.js +4 -0
  278. package/dist/src/storage/providers/sqlite/schema-tables-1.js.map +1 -1
  279. package/dist/src/storage/providers/sqlite/schema-tables-3.d.ts.map +1 -1
  280. package/dist/src/storage/providers/sqlite/schema-tables-3.js +106 -0
  281. package/dist/src/storage/providers/sqlite/schema-tables-3.js.map +1 -1
  282. package/dist/src/storage/providers/sqlite/schema.d.ts.map +1 -1
  283. package/dist/src/storage/providers/sqlite/schema.js +2 -0
  284. package/dist/src/storage/providers/sqlite/schema.js.map +1 -1
  285. package/dist/src/storage/repositories/connection.repository.d.ts +124 -0
  286. package/dist/src/storage/repositories/connection.repository.d.ts.map +1 -0
  287. package/dist/src/storage/repositories/connection.repository.js +2 -0
  288. package/dist/src/storage/repositories/connection.repository.js.map +1 -0
  289. package/dist/src/storage/types/agents-messaging.d.ts +19 -0
  290. package/dist/src/storage/types/agents-messaging.d.ts.map +1 -1
  291. package/dist/src/storage/types/agents-messaging.js.map +1 -1
  292. package/dist/src/storage/types/auth.d.ts +8 -1
  293. package/dist/src/storage/types/auth.d.ts.map +1 -1
  294. package/dist/src/utils/build-stamp.d.ts +56 -0
  295. package/dist/src/utils/build-stamp.d.ts.map +1 -0
  296. package/dist/src/utils/build-stamp.js +142 -0
  297. package/dist/src/utils/build-stamp.js.map +1 -0
  298. package/dist/src/utils/messaging.d.ts +14 -0
  299. package/dist/src/utils/messaging.d.ts.map +1 -1
  300. package/dist/src/utils/messaging.js +0 -0
  301. package/dist/src/utils/messaging.js.map +1 -1
  302. package/dist/static/sdk-libs/connect/index.js +199 -0
  303. package/dist/static/sdk-libs/connect/notes.js +47 -0
  304. package/dist/static/sdk-libs/connect/panel.js +238 -0
  305. package/dist/static/sdk-libs/data/index.js +63 -11
  306. package/dist/static/sdk-libs/dist/aimeat-connect.js +357 -0
  307. package/dist/static/sdk-libs/dist/aimeat-data.js +40 -9
  308. package/package.json +2 -2
@@ -0,0 +1,118 @@
1
+ /**
2
+ * @file providers.ts
3
+ * @description Registry of OUTBOUND connection providers (TARGET-057) — the services a principal
4
+ * can connect their own account at. Mirrors the shape of services/oidc-providers.ts, which is the
5
+ * inbound half, and is deliberately a separate registry: signing IN with Google and PUBLISHING to
6
+ * a Google account are different directions, different consent and different client credentials.
7
+ *
8
+ * THE CAPABILITY IS OFF UNTIL IT IS CONFIGURED. A provider is `enabled` only when the node has
9
+ * what it needs to talk to it. Nothing here fails open, and nothing here half-works: an
10
+ * unconfigured provider is absent from discovery and refused at start, with a reason.
11
+ *
12
+ * Two axes decide everything else about a provider, and both were chosen because getting either
13
+ * wrong is invisible until the third provider:
14
+ * - `credentialShape` — oauth2 | static | session. Designing around oauth2 alone produces a
15
+ * store that cannot hold a Bluesky app password.
16
+ * - `instanceScoped` — whether the provider IS one endpoint. Mastodon is not: its client
17
+ * credentials are per instance and acquired at runtime (see storage ProviderClient).
18
+ * @structure
19
+ * - OutboundProvider — the descriptor
20
+ * - buildOutboundProviders(config) — the enabled list, gated on configuration
21
+ * - findProvider(list, id) / listProviderMeta(list) — lookup + the safe public projection
22
+ * @usage const providers = buildOutboundProviders(config);
23
+ * @version-history
24
+ * v1.0.0 — 2026-08-02 — TARGET-057 Phase 1b. Mastodon, YouTube, Bluesky.
25
+ */
26
+ import type { AimeatConfig } from '../../config.js';
27
+ import type { CredentialShape } from '../../models/connection-schemas.js';
28
+ /** Stable provider identifiers. Also the value stored in `Connection.provider`. */
29
+ export type OutboundProviderId = 'mastodon' | 'youtube' | 'bluesky' | 'fake' | 'fake-static';
30
+ /**
31
+ * What a user must supply for a provider that has NO authorization round.
32
+ *
33
+ * Declared here rather than hardcoded in a form so the panel renders whatever a provider needs
34
+ * without knowing about that provider. A provider with `attachFields: null` uses the OAuth round
35
+ * instead, and the two paths never overlap.
36
+ */
37
+ export interface AttachField {
38
+ name: string;
39
+ label: string;
40
+ /** Rendered as a password input, and never echoed back in any response. */
41
+ secret: boolean;
42
+ placeholder?: string;
43
+ }
44
+ /** OAuth2 endpoints. Derived from the instance origin for an instance-scoped provider. */
45
+ export interface OAuthEndpoints {
46
+ authorize: string;
47
+ token: string;
48
+ /** Null when the provider offers no revocation endpoint — revoking is then local-only. */
49
+ revoke: string | null;
50
+ }
51
+ export interface OutboundProvider {
52
+ id: OutboundProviderId;
53
+ /** Fallback English label; the SDK lib overrides it from i18n. */
54
+ label: string;
55
+ credentialShape: CredentialShape;
56
+ /**
57
+ * True when the provider is a FEDERATION rather than one endpoint. Client credentials are then
58
+ * per instance and acquired at runtime; `client` is null and `endpoints()` needs the instance.
59
+ */
60
+ instanceScoped: boolean;
61
+ /** Config-gated. False = absent from discovery and refused at start, with a reason. */
62
+ enabled: boolean;
63
+ /** Why it is disabled, in words an operator can act on. Null when enabled. */
64
+ disabledReason: string | null;
65
+ /** Fixed-endpoint client credentials from config. Null for an instance-scoped provider. */
66
+ client: {
67
+ id: string;
68
+ secret: string;
69
+ } | null;
70
+ /** Scopes requested at authorize time. Empty for a `static` credential. */
71
+ scopes: string[];
72
+ /** Whether to send a PKCE challenge. Always true where the provider supports it. */
73
+ pkce: boolean;
74
+ /**
75
+ * What an app may ASK about a connection at this provider (decision K1). An app never reads the
76
+ * provider's own scope vocabulary — it cannot know what those names mean — so it asks a question
77
+ * in AIMEAT's vocabulary and gets a yes or no.
78
+ */
79
+ capabilities: string[];
80
+ /**
81
+ * The provider's own daily ceiling on publishes, when it has one that is shared rather than
82
+ * per-user. YouTube's allowance is per Google PROJECT, so ten publishers on one shared channel
83
+ * close it before lunch unless somebody counts.
84
+ *
85
+ * null means "no known shared ceiling", which is the honest value until the real number has been
86
+ * READ from the provider's console rather than guessed. The counting mechanism does not wait for
87
+ * it — publish-gate measures usage either way, so the number can be filled in with evidence.
88
+ */
89
+ sharedDailyLimit: number | null;
90
+ /**
91
+ * Non-null when this provider is connected by SUPPLYING a credential rather than by an
92
+ * authorization round. Null for an OAuth provider. Advertising a provider without one of the two
93
+ * is how a "Connect" button appears that cannot work.
94
+ */
95
+ attachFields: AttachField[] | null;
96
+ /** Endpoints. `instance` is required exactly when `instanceScoped` is true. */
97
+ endpoints(instance: string | null): OAuthEndpoints | null;
98
+ }
99
+ /** What discovery may show. Deliberately free of anything an app could not act on. */
100
+ export interface OutboundProviderMeta {
101
+ id: OutboundProviderId;
102
+ label: string;
103
+ instanceScoped: boolean;
104
+ credentialShape: CredentialShape;
105
+ capabilities: string[];
106
+ attachFields: AttachField[] | null;
107
+ }
108
+ /**
109
+ * The providers this node offers. Disabled ones are RETURNED rather than filtered, so a route can
110
+ * answer "why can I not connect YouTube" with the reason instead of a bare absence — an operator
111
+ * staring at an empty list has nothing to act on.
112
+ */
113
+ export declare function buildOutboundProviders(config: AimeatConfig): OutboundProvider[];
114
+ /** Lookup by id. Returns disabled providers too; the caller decides what to do about that. */
115
+ export declare function findProvider(providers: OutboundProvider[], id: string): OutboundProvider | undefined;
116
+ /** The public projection for discovery. Enabled providers only, and no credentials in it. */
117
+ export declare function listProviderMeta(providers: OutboundProvider[]): OutboundProviderMeta[];
118
+ //# sourceMappingURL=providers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"providers.d.ts","sourceRoot":"","sources":["../../../../src/services/connections/providers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oCAAoC,CAAC;AAE1E,mFAAmF;AACnF,MAAM,MAAM,kBAAkB,GAAG,UAAU,GAAG,SAAS,GAAG,SAAS,GAAG,MAAM,GAAG,aAAa,CAAC;AAE7F;;;;;;GAMG;AACH,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,2EAA2E;IAC3E,MAAM,EAAE,OAAO,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,0FAA0F;AAC1F,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,0FAA0F;IAC1F,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB;AAED,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,kBAAkB,CAAC;IACvB,kEAAkE;IAClE,KAAK,EAAE,MAAM,CAAC;IACd,eAAe,EAAE,eAAe,CAAC;IACjC;;;OAGG;IACH,cAAc,EAAE,OAAO,CAAC;IACxB,uFAAuF;IACvF,OAAO,EAAE,OAAO,CAAC;IACjB,8EAA8E;IAC9E,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,2FAA2F;IAC3F,MAAM,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IAC9C,2EAA2E;IAC3E,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,oFAAoF;IACpF,IAAI,EAAE,OAAO,CAAC;IACd;;;;OAIG;IACH,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB;;;;;;;;OAQG;IACH,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC;;;;OAIG;IACH,YAAY,EAAE,WAAW,EAAE,GAAG,IAAI,CAAC;IACnC,+EAA+E;IAC/E,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,cAAc,GAAG,IAAI,CAAC;CAC3D;AAED,sFAAsF;AACtF,MAAM,WAAW,oBAAoB;IACnC,EAAE,EAAE,kBAAkB,CAAC;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,cAAc,EAAE,OAAO,CAAC;IACxB,eAAe,EAAE,eAAe,CAAC;IACjC,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,YAAY,EAAE,WAAW,EAAE,GAAG,IAAI,CAAC;CACpC;AA6MD;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,YAAY,GAAG,gBAAgB,EAAE,CAa/E;AAED,8FAA8F;AAC9F,wBAAgB,YAAY,CAC1B,SAAS,EAAE,gBAAgB,EAAE,EAAE,EAAE,EAAE,MAAM,GACxC,gBAAgB,GAAG,SAAS,CAE9B;AAED,6FAA6F;AAC7F,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,gBAAgB,EAAE,GAAG,oBAAoB,EAAE,CAStF"}
@@ -0,0 +1,260 @@
1
+ /**
2
+ * @file providers.ts
3
+ * @description Registry of OUTBOUND connection providers (TARGET-057) — the services a principal
4
+ * can connect their own account at. Mirrors the shape of services/oidc-providers.ts, which is the
5
+ * inbound half, and is deliberately a separate registry: signing IN with Google and PUBLISHING to
6
+ * a Google account are different directions, different consent and different client credentials.
7
+ *
8
+ * THE CAPABILITY IS OFF UNTIL IT IS CONFIGURED. A provider is `enabled` only when the node has
9
+ * what it needs to talk to it. Nothing here fails open, and nothing here half-works: an
10
+ * unconfigured provider is absent from discovery and refused at start, with a reason.
11
+ *
12
+ * Two axes decide everything else about a provider, and both were chosen because getting either
13
+ * wrong is invisible until the third provider:
14
+ * - `credentialShape` — oauth2 | static | session. Designing around oauth2 alone produces a
15
+ * store that cannot hold a Bluesky app password.
16
+ * - `instanceScoped` — whether the provider IS one endpoint. Mastodon is not: its client
17
+ * credentials are per instance and acquired at runtime (see storage ProviderClient).
18
+ * @structure
19
+ * - OutboundProvider — the descriptor
20
+ * - buildOutboundProviders(config) — the enabled list, gated on configuration
21
+ * - findProvider(list, id) / listProviderMeta(list) — lookup + the safe public projection
22
+ * @usage const providers = buildOutboundProviders(config);
23
+ * @version-history
24
+ * v1.0.0 — 2026-08-02 — TARGET-057 Phase 1b. Mastodon, YouTube, Bluesky.
25
+ */
26
+ /**
27
+ * Mastodon. The awkward one, and the reason the store carries an `instance` column at all: the same
28
+ * handle at two instances is two accounts, and the client credentials are issued per instance by
29
+ * `POST /api/v1/apps` with no human in the loop. There is nothing to put in .env because nobody
30
+ * knows which instance the next user arrives from.
31
+ */
32
+ function mastodon(enabled) {
33
+ return {
34
+ id: 'mastodon',
35
+ label: 'Mastodon',
36
+ credentialShape: 'oauth2',
37
+ instanceScoped: true,
38
+ enabled,
39
+ disabledReason: enabled ? null : 'connections capability is off (AIMEAT_CONNECTIONS_ENABLED)',
40
+ client: null,
41
+ scopes: ['read:accounts', 'write:statuses', 'write:media'],
42
+ pkce: true,
43
+ capabilities: ['publish-post', 'publish-video'],
44
+ attachFields: null,
45
+ // Instances rate-limit, but there is no single daily publish ceiling to state, and inventing
46
+ // one would be a guess wearing a number.
47
+ sharedDailyLimit: null,
48
+ endpoints(instance) {
49
+ // The caller validates and normalises `instance` before this is reached; building a URL from
50
+ // an unvalidated user-supplied host is exactly the SSRF this feature has to not have.
51
+ if (!instance)
52
+ return null;
53
+ return {
54
+ authorize: `${instance}/oauth/authorize`,
55
+ token: `${instance}/oauth/token`,
56
+ revoke: `${instance}/oauth/revoke`,
57
+ };
58
+ },
59
+ };
60
+ }
61
+ /**
62
+ * YouTube via Google. One endpoint, one client, credentials from config.
63
+ *
64
+ * `access_type=offline` + `prompt=consent` are added at authorize time by the OAuth service, not
65
+ * here: without them Google returns no refresh token at all on a repeat authorization, and the
66
+ * connection silently becomes a one-hour connection that dies and cannot renew.
67
+ */
68
+ function youtube(clientId, clientSecret, capabilityOn) {
69
+ const configured = Boolean(clientId && clientSecret);
70
+ const enabled = capabilityOn && configured;
71
+ return {
72
+ id: 'youtube',
73
+ label: 'YouTube',
74
+ credentialShape: 'oauth2',
75
+ instanceScoped: false,
76
+ enabled,
77
+ disabledReason: enabled
78
+ ? null
79
+ : !capabilityOn
80
+ ? 'connections capability is off (AIMEAT_CONNECTIONS_ENABLED)'
81
+ : 'no client credentials (AIMEAT_CONNECT_GOOGLE_CLIENT_ID / _SECRET)',
82
+ client: configured ? { id: clientId, secret: clientSecret } : null,
83
+ // BOTH, and the second one is not optional. `youtube.upload` grants the write and nothing else,
84
+ // so `channels.list?mine=true` — how the node learns WHICH channel this connection is for —
85
+ // comes back 403 with a valid token. Asking only for the write and then reading is a
86
+ // contradiction that shows up at the very last step of a user's first connection attempt.
87
+ // The channel identity is what the dedupe key and the account label are built from, so this is
88
+ // the narrowest pair that actually works rather than a convenience.
89
+ scopes: [
90
+ 'https://www.googleapis.com/auth/youtube.upload',
91
+ 'https://www.googleapis.com/auth/youtube.readonly',
92
+ ],
93
+ pkce: true,
94
+ capabilities: ['publish-video'],
95
+ attachFields: null,
96
+ // SIX. Read from the project's own quota page on 2026-08-02, not guessed:
97
+ //
98
+ // Queries per day .......... 10,000 <- the budget, and the one that binds
99
+ // Video Uploads per day ....... 100 <- looks like the limit, and is not
100
+ //
101
+ // The allowance is spent in UNITS, and one videos.insert costs 1,600 of them, so the budget
102
+ // runs out after six uploads while the upload counter is still at 6 of 100. Anyone reading that
103
+ // page would take the 100 and be wrong by a factor of sixteen.
104
+ //
105
+ // It is per Google PROJECT, so this is six uploads a day for EVERY publisher on the node
106
+ // combined — which is exactly why a shared channel needs a per-publisher cap on top.
107
+ //
108
+ // The 1,600 is Google's documented per-call cost rather than something measured here. The
109
+ // measurement is one step away and belongs to the first real upload: the quota page shows
110
+ // Current usage, so a single publish either moves it by 1,600 or corrects this number. (It
111
+ // already reads 1 from the channels.list the node makes when an account is connected.)
112
+ sharedDailyLimit: 6,
113
+ endpoints() {
114
+ return {
115
+ authorize: 'https://accounts.google.com/o/oauth2/v2/auth',
116
+ token: 'https://oauth2.googleapis.com/token',
117
+ revoke: 'https://oauth2.googleapis.com/revoke',
118
+ };
119
+ },
120
+ };
121
+ }
122
+ /**
123
+ * Bluesky. Present in the first slice specifically because it is NOT oauth2-shaped: an app password
124
+ * exchanged for a session. A store that only ever saw Mastodon and YouTube would be built around
125
+ * authorization codes, and the mistake would surface at the third provider rather than the first.
126
+ *
127
+ * It is also the one place a user copies a secret to us. That is worse than a consent screen and
128
+ * the connect dialog has to say so plainly.
129
+ */
130
+ function bluesky(capabilityOn) {
131
+ return {
132
+ id: 'bluesky',
133
+ label: 'Bluesky',
134
+ // What is STORED is a session, even though what the user supplies is a static app password.
135
+ // Both are kept: the session is what calls use, and the app password is what lets a dead
136
+ // session be re-minted without asking the user to go and find it again.
137
+ credentialShape: 'session',
138
+ instanceScoped: false,
139
+ enabled: capabilityOn,
140
+ disabledReason: capabilityOn ? null : 'connections capability is off (AIMEAT_CONNECTIONS_ENABLED)',
141
+ // No client credentials at all: the user's app password IS the credential.
142
+ client: null,
143
+ scopes: [],
144
+ pkce: false,
145
+ // publish-post ONLY, and publish-video is deliberately absent. Video on Bluesky goes through a
146
+ // separate video service with its own job queue and limits, which is not built. Listing a
147
+ // capability the recipe cannot perform is the same "advertised but unconnectable" mistake the
148
+ // attach route was just fixed for, one field over.
149
+ capabilities: ['publish-post'],
150
+ sharedDailyLimit: null,
151
+ // The one provider a user hands us a secret for, so it is the one that needs a form.
152
+ attachFields: [
153
+ { name: 'identifier', label: 'Handle', secret: false, placeholder: 'you.bsky.social' },
154
+ { name: 'password', label: 'App password', secret: true, placeholder: 'xxxx-xxxx-xxxx-xxxx' },
155
+ ],
156
+ endpoints() {
157
+ // Not an OAuth2 flow. The session endpoints live in the attach recipe, not here.
158
+ return null;
159
+ },
160
+ };
161
+ }
162
+ /**
163
+ * A stand-in provider for the end-to-end tests. Present ONLY when a base URL is configured, which
164
+ * nothing but the E2E environment does, so it cannot appear on a real node.
165
+ *
166
+ * It exists because the alternative is mocking the connection service, and a mocked service proves
167
+ * the mock. Against a real HTTP server the tests drive the actual code path: state, PKCE, the token
168
+ * exchange, the identity lookup, a ROTATING refresh token and revocation. The rotation is the point
169
+ * — it is the provider behaviour that makes concurrent refresh destructive, and it cannot be
170
+ * demonstrated against a stub that always returns the same token.
171
+ */
172
+ function fake(baseUrl, capabilityOn) {
173
+ const enabled = capabilityOn && Boolean(baseUrl);
174
+ return {
175
+ id: 'fake',
176
+ label: 'Test provider',
177
+ credentialShape: 'oauth2',
178
+ instanceScoped: false,
179
+ enabled,
180
+ disabledReason: enabled ? null : 'no AIMEAT_CONNECT_FAKE_BASE_URL (this provider is test-only)',
181
+ client: baseUrl ? { id: 'fake-client', secret: 'fake-secret' } : null,
182
+ scopes: ['publish'],
183
+ pkce: true,
184
+ capabilities: ['publish-video', 'publish-post'],
185
+ sharedDailyLimit: null,
186
+ attachFields: null,
187
+ endpoints() {
188
+ if (!baseUrl)
189
+ return null;
190
+ return {
191
+ authorize: `${baseUrl}/authorize`,
192
+ token: `${baseUrl}/token`,
193
+ revoke: `${baseUrl}/revoke`,
194
+ };
195
+ },
196
+ };
197
+ }
198
+ /**
199
+ * The session-shaped test provider. Exists for the same reason `fake` does, one axis over: the
200
+ * supplied-credential path (no authorization round, a session minted from a secret the user hands
201
+ * over, and a refresh that is not OAuth2) has to be provable without a real Bluesky account.
202
+ *
203
+ * Without it, "attach" would ship tested only against the one provider nobody on this node has.
204
+ */
205
+ function fakeStatic(baseUrl, capabilityOn) {
206
+ const enabled = capabilityOn && Boolean(baseUrl);
207
+ return {
208
+ id: 'fake-static',
209
+ label: 'Test provider (supplied credential)',
210
+ credentialShape: 'session',
211
+ instanceScoped: false,
212
+ enabled,
213
+ disabledReason: enabled ? null : 'no AIMEAT_CONNECT_FAKE_BASE_URL (this provider is test-only)',
214
+ client: null,
215
+ scopes: [],
216
+ pkce: false,
217
+ capabilities: ['publish-post'],
218
+ sharedDailyLimit: null,
219
+ attachFields: [
220
+ { name: 'identifier', label: 'Handle', secret: false, placeholder: 'someone' },
221
+ { name: 'password', label: 'Secret', secret: true },
222
+ ],
223
+ endpoints() { return null; },
224
+ };
225
+ }
226
+ /**
227
+ * The providers this node offers. Disabled ones are RETURNED rather than filtered, so a route can
228
+ * answer "why can I not connect YouTube" with the reason instead of a bare absence — an operator
229
+ * staring at an empty list has nothing to act on.
230
+ */
231
+ export function buildOutboundProviders(config) {
232
+ const on = config.connectionsEnabled;
233
+ const list = [
234
+ mastodon(on),
235
+ youtube(config.connectGoogleClientId, config.connectGoogleClientSecret, on),
236
+ bluesky(on),
237
+ ];
238
+ // Appended only when configured, so a production node's list is exactly the three above.
239
+ if (config.connectFakeBaseUrl) {
240
+ list.push(fake(config.connectFakeBaseUrl, on));
241
+ list.push(fakeStatic(config.connectFakeBaseUrl, on));
242
+ }
243
+ return list;
244
+ }
245
+ /** Lookup by id. Returns disabled providers too; the caller decides what to do about that. */
246
+ export function findProvider(providers, id) {
247
+ return providers.find((p) => p.id === id);
248
+ }
249
+ /** The public projection for discovery. Enabled providers only, and no credentials in it. */
250
+ export function listProviderMeta(providers) {
251
+ return providers.filter((p) => p.enabled).map((p) => ({
252
+ id: p.id,
253
+ label: p.label,
254
+ instanceScoped: p.instanceScoped,
255
+ credentialShape: p.credentialShape,
256
+ capabilities: p.capabilities,
257
+ attachFields: p.attachFields,
258
+ }));
259
+ }
260
+ //# sourceMappingURL=providers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"providers.js","sourceRoot":"","sources":["../../../../src/services/connections/providers.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,103 @@
1
+ /**
2
+ * @file publish-gate.ts
3
+ * @description Everything that must be true before a publish leaves the node (TARGET-057), in one
4
+ * place so a caller cannot satisfy three of the four checks.
5
+ *
6
+ * THE ORDER IS THE POINT. The attempt is recorded BEFORE it is tried. A retry that races a slow
7
+ * success publishes the video twice, and this repository has produced that family of bug three
8
+ * times. The idempotency key is deterministic, so a retry recomputes it without having to remember
9
+ * anything, and the store's unique index arbitrates.
10
+ *
11
+ * AN APP CALLS A DELEGATION, NEVER A CONNECTION. What the app sends is merged UNDER the
12
+ * delegation's fixed parameters, so it cannot retarget the channel, the visibility or the
13
+ * playlist. Merging the other way round would turn a narrow errand into a power of attorney, and
14
+ * it is one character of difference in the spread.
15
+ *
16
+ * A FULL QUOTA IS NOT A FAILURE. It queues, with a reason. So does moderation. Reporting either as
17
+ * an error teaches an app to retry, which is the one response that makes both worse.
18
+ * @structure buildIdempotencyKey · openPublish · quotaStatus
19
+ * @usage import { openPublish } from './publish-gate.js';
20
+ * @version-history
21
+ * v1.0.0 — 2026-08-02 — TARGET-057 Phase 1d.
22
+ */
23
+ import type { Storage } from '../../storage/interface.js';
24
+ import type { ConnectionRecord, DelegationRecord, PublishAttempt } from '../../models/connection-schemas.js';
25
+ export interface PublishRequest {
26
+ /** WHO is publishing. In shared mode the app's user, not the connection's principal. */
27
+ publisher: string;
28
+ appId: string;
29
+ action: string;
30
+ storageKey: string;
31
+ /** Free text the app chose. Part of the idempotency key: a different caption is a different post. */
32
+ caption: string;
33
+ /** What the app asked for. Merged UNDER the delegation's fixed parameters. */
34
+ params?: Record<string, unknown>;
35
+ }
36
+ export type OpenPublishResult = {
37
+ ok: true;
38
+ /** True when this call did NOT open new work — the key already existed. */
39
+ replay: boolean;
40
+ attempt: PublishAttempt;
41
+ connection: ConnectionRecord;
42
+ delegation: DelegationRecord;
43
+ /** The app's params with the delegation's fixed ones layered on top. */
44
+ params: Record<string, unknown>;
45
+ } | {
46
+ ok: false;
47
+ code: string;
48
+ reason: string;
49
+ };
50
+ /**
51
+ * Deterministic over the things that make one publish a DIFFERENT publish. A retry of the same
52
+ * request recomputes the same key with nothing carried between attempts, which is what lets an
53
+ * interrupted caller be honest about not knowing whether the first try landed.
54
+ */
55
+ export declare function buildIdempotencyKey(publisher: string, connectionId: string, storageKey: string, caption: string): string;
56
+ /**
57
+ * Run every gate and open the attempt.
58
+ *
59
+ * The caller performs no check of its own afterwards: if this returns ok it has already decided the
60
+ * publisher is allowed, the delegation is live, the connection is usable, the caps are not spent and
61
+ * the attempt is recorded. Splitting these across caller and service is how one of them gets skipped.
62
+ */
63
+ export declare function openPublish(storage: Storage, req: PublishRequest, opts: {
64
+ sharedDailyLimit: number | null;
65
+ }): Promise<OpenPublishResult>;
66
+ /**
67
+ * Open a publish to the caller's OWN connection — no delegation involved.
68
+ *
69
+ * The gate above is built around a delegation because that is where the interesting constraints
70
+ * live, and it left the ordinary case with no path at all: publishing to an account you connected
71
+ * yourself. There is nobody to delegate to and no per-publisher cap to apply, because the publisher
72
+ * and the account holder are the same person.
73
+ *
74
+ * What still applies, and is the reason this is not just a direct call to the recipe:
75
+ * - the connection must be usable, and `needs_reauth` must say so before anything is uploaded
76
+ * - the provider's SHARED ceiling is per project, so a personal publish spends the same allowance
77
+ * a shared channel does and has to be counted against it
78
+ * - the attempt is recorded BEFORE it is tried, for exactly the same reason
79
+ */
80
+ export declare function openOwnPublish(storage: Storage, req: Omit<PublishRequest, 'appId' | 'action'> & {
81
+ connectionId: string;
82
+ }, opts: {
83
+ sharedDailyLimit: number | null;
84
+ }): Promise<OpenPublishResult | {
85
+ ok: false;
86
+ code: string;
87
+ reason: string;
88
+ }>;
89
+ /** What the owner's panel shows about a shared channel's allowance. */
90
+ export interface QuotaStatus {
91
+ limit: number | null;
92
+ usedInWindow: number;
93
+ remaining: number | null;
94
+ windowHours: number;
95
+ }
96
+ /**
97
+ * How much of the shared allowance is left.
98
+ *
99
+ * Read separately from the gate so the owner can see it BEFORE anything is refused. A ceiling a
100
+ * person only meets by hitting it is indistinguishable from a broken feature.
101
+ */
102
+ export declare function quotaStatus(storage: Storage, delegationId: string, sharedDailyLimit: number | null): Promise<QuotaStatus>;
103
+ //# sourceMappingURL=publish-gate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"publish-gate.d.ts","sourceRoot":"","sources":["../../../../src/services/connections/publish-gate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAGH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,4BAA4B,CAAC;AAC1D,OAAO,KAAK,EACV,gBAAgB,EAAE,gBAAgB,EAAE,cAAc,EACnD,MAAM,oCAAoC,CAAC;AAK5C,MAAM,WAAW,cAAc;IAC7B,wFAAwF;IACxF,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,qGAAqG;IACrG,OAAO,EAAE,MAAM,CAAC;IAChB,8EAA8E;IAC9E,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAClC;AAED,MAAM,MAAM,iBAAiB,GACzB;IACA,EAAE,EAAE,IAAI,CAAC;IACT,2EAA2E;IAC3E,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,cAAc,CAAC;IACxB,UAAU,EAAE,gBAAgB,CAAC;IAC7B,UAAU,EAAE,gBAAgB,CAAC;IAC7B,wEAAwE;IACxE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACjC,GACC;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAEhD;;;;GAIG;AACH,wBAAgB,mBAAmB,CACjC,SAAS,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAC3E,MAAM,CAIR;AAED;;;;;;GAMG;AACH,wBAAsB,WAAW,CAC/B,OAAO,EAAE,OAAO,EAChB,GAAG,EAAE,cAAc,EACnB,IAAI,EAAE;IAAE,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,GACxC,OAAO,CAAC,iBAAiB,CAAC,CA+F5B;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAsB,cAAc,CAClC,OAAO,EAAE,OAAO,EAChB,GAAG,EAAE,IAAI,CAAC,cAAc,EAAE,OAAO,GAAG,QAAQ,CAAC,GAAG;IAAE,YAAY,EAAE,MAAM,CAAA;CAAE,EACxE,IAAI,EAAE;IAAE,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,GACxC,OAAO,CAAC,iBAAiB,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAoD1E;AAED,uEAAuE;AACvE,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;;;;GAKG;AACH,wBAAsB,WAAW,CAC/B,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,GAAG,IAAI,GACtE,OAAO,CAAC,WAAW,CAAC,CAatB"}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"publish-gate.js","sourceRoot":"","sources":["../../../../src/services/connections/publish-gate.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,60 @@
1
+ /**
2
+ * @file publish.ts
3
+ * @description The recipes that actually put something on a provider (TARGET-057 phase 7b). One
4
+ * function per provider, behind one interface, driven by the gate in publish-gate.ts.
5
+ *
6
+ * WHERE THIS LIVES, AND A DELIBERATE DEVIATION FROM THE SPEC. doc-t057-connect-spec puts recipes
7
+ * in an extension so a provider's endpoints can change without a node deploy. That reason is
8
+ * real and it still holds. It is not done yet, because the extension path needs two things that
9
+ * do not exist — a `ctx.connection()` binding into the sandbox and a streaming upload that keeps
10
+ * the bytes out of QuickJS — and building both before a single publish has ever succeeded would
11
+ * be designing the seam before knowing its shape. The house rule applies: a primitive is
12
+ * extracted when it has a second consumer, not before. `PublishRecipe` below is the seam, kept
13
+ * deliberately narrow so the move is a relocation rather than a redesign.
14
+ *
15
+ * PERMANENT AND TEMPORARY ARE DIFFERENT ANSWERS. A provider refusing the CONTENT is final and
16
+ * must never be retried; a provider being unreachable is not. Collapsing the two is how a
17
+ * rejected video gets resubmitted forever, and how an outage looks like a rejection.
18
+ * @structure PublishRecipe · publishToProvider · mastodonPublish · blueskyPost · youtubeUpload
19
+ * @usage import { publishToProvider } from './publish.js';
20
+ * @version-history
21
+ * v1.0.0 — 2026-08-02 — TARGET-057 phase 7b. Mastodon video, Bluesky text, YouTube resumable.
22
+ */
23
+ import type { ConnectionCredential, ConnectionRecord } from '../../models/connection-schemas.js';
24
+ import type { OutboundProvider } from './providers.js';
25
+ /** What a recipe is handed. `params` already has the delegation's fixed values layered on top. */
26
+ export interface PublishInput {
27
+ /** The provider descriptor, so a recipe reads its own endpoints instead of being handed them. */
28
+ provider: OutboundProvider;
29
+ connection: ConnectionRecord;
30
+ credential: ConnectionCredential;
31
+ caption: string;
32
+ params: Record<string, unknown>;
33
+ file: {
34
+ bytes: Buffer;
35
+ mimeType: string;
36
+ name: string;
37
+ } | null;
38
+ }
39
+ export type PublishOutcome = {
40
+ ok: true;
41
+ externalRef: string;
42
+ } | {
43
+ ok: false;
44
+ /**
45
+ * True when the provider refused the CONTENT or the grant — retrying changes nothing and the
46
+ * owner has to act. False for anything transport-shaped, which is worth another attempt.
47
+ */
48
+ permanent: boolean;
49
+ reason: string;
50
+ };
51
+ export type PublishRecipe = (input: PublishInput) => Promise<PublishOutcome>;
52
+ /**
53
+ * Run the recipe for a connection's provider.
54
+ *
55
+ * A provider with no recipe is a refusal rather than a silent no-op: the gate has already recorded
56
+ * an attempt by the time this is called, and leaving it in flight forever would be worse than
57
+ * saying so.
58
+ */
59
+ export declare function publishToProvider(input: PublishInput): Promise<PublishOutcome>;
60
+ //# sourceMappingURL=publish.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"publish.d.ts","sourceRoot":"","sources":["../../../../src/services/connections/publish.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAIH,OAAO,KAAK,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,MAAM,oCAAoC,CAAC;AACjG,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAEvD,kGAAkG;AAClG,MAAM,WAAW,YAAY;IAC3B,iGAAiG;IACjG,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,UAAU,EAAE,gBAAgB,CAAC;IAC7B,UAAU,EAAE,oBAAoB,CAAC;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;CAChE;AAED,MAAM,MAAM,cAAc,GACtB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,GACjC;IACA,EAAE,EAAE,KAAK,CAAC;IACV;;;OAGG;IACH,SAAS,EAAE,OAAO,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEJ,MAAM,MAAM,aAAa,GAAG,CAAC,KAAK,EAAE,YAAY,KAAK,OAAO,CAAC,cAAc,CAAC,CAAC;AA4S7E;;;;;;GAMG;AACH,wBAAsB,iBAAiB,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,cAAc,CAAC,CAMpF"}