@zackbart/connecta 0.28.1 → 0.29.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 (319) hide show
  1. package/CHANGELOG.md +788 -5
  2. package/README.md +62 -42
  3. package/bin/connecta.mjs +110 -139
  4. package/bin/meta-tool-names.d.mts +2 -0
  5. package/bin/meta-tool-names.mjs +9 -0
  6. package/bin/version.mjs +3 -0
  7. package/dist/access-tokens.js +53 -63
  8. package/dist/activity-request.js +8 -0
  9. package/dist/activity.d.ts +76 -42
  10. package/dist/activity.js +110 -42
  11. package/dist/auth/clerk-sdk/client.d.ts +65 -0
  12. package/dist/auth/clerk-sdk/client.js +5 -0
  13. package/dist/auth/clerk-sdk/generated.js +1845 -0
  14. package/dist/auth/clerk-transport.js +19 -0
  15. package/dist/auth/clerk.d.ts +17 -7
  16. package/dist/auth/clerk.js +189 -107
  17. package/dist/auth/cloudflare-access.js +25 -26
  18. package/dist/auth/downstream-client-metadata.d.ts +29 -0
  19. package/dist/auth/downstream-client-metadata.js +133 -0
  20. package/dist/auth/downstream-oauth.js +1584 -1580
  21. package/dist/auth/downstream-revocation.js +106 -0
  22. package/dist/auth/oauth-token-response.js +231 -0
  23. package/dist/auth/oauth-v2-migration.js +116 -0
  24. package/dist/auth/static-oauth.js +93 -71
  25. package/dist/auth-elicitation.js +283 -0
  26. package/dist/branding.d.ts +8 -16
  27. package/dist/branding.js +26 -59
  28. package/dist/byte-read-response.js +39 -0
  29. package/dist/call-admission.js +12 -16
  30. package/dist/catalog-cache.js +739 -0
  31. package/dist/catalog-drift.d.ts +50 -15
  32. package/dist/catalog-drift.js +365 -128
  33. package/dist/catalog-fingerprint.js +2 -4
  34. package/dist/catalog-freshness.js +13 -0
  35. package/dist/catalog-limits.js +2 -2
  36. package/dist/catalog-service.js +368 -224
  37. package/dist/catalog.js +43 -84
  38. package/dist/concurrency.js +3 -4
  39. package/dist/config-defaults.d.ts +39 -0
  40. package/dist/config-defaults.js +46 -0
  41. package/dist/config-schema.d.ts +181 -0
  42. package/dist/config-schema.js +435 -0
  43. package/dist/config-value-sources.js +102 -0
  44. package/dist/config.d.ts +631 -0
  45. package/dist/config.js +503 -0
  46. package/dist/connector-access.d.ts +1 -0
  47. package/dist/connector-access.js +13 -15
  48. package/dist/connector-caller.d.ts +8 -0
  49. package/dist/connector-caller.js +15 -6
  50. package/dist/connector-scope.js +1 -1
  51. package/dist/connectors/api-connector.d.ts +59 -7
  52. package/dist/connectors/api-connector.js +106 -19
  53. package/dist/connectors/api.js +4 -1
  54. package/dist/connectors/guarded-fetch.d.ts +144 -0
  55. package/dist/connectors/guarded-fetch.js +84 -35
  56. package/dist/connectors/negotiation-cache.js +46 -0
  57. package/dist/connectors/option-shapes.js +27 -0
  58. package/dist/connectors/remote-mcp.d.ts +30 -4
  59. package/dist/connectors/remote-mcp.js +1774 -320
  60. package/dist/connectors/resource-uri.js +335 -0
  61. package/dist/credential-contract.d.ts +10 -0
  62. package/dist/credential-rules.js +1 -3
  63. package/dist/credential-url.js +108 -0
  64. package/dist/credentials.d.ts +6 -1
  65. package/dist/credentials.js +27 -18
  66. package/dist/d1.d.ts +130 -0
  67. package/dist/d1.js +290 -0
  68. package/dist/describe-config.d.ts +165 -0
  69. package/dist/describe-config.js +315 -0
  70. package/dist/described.js +106 -0
  71. package/dist/downstream-input-context.js +119 -0
  72. package/dist/downstream-input.js +323 -0
  73. package/dist/errors.d.ts +97 -20
  74. package/dist/errors.js +158 -80
  75. package/dist/execute.js +453 -305
  76. package/dist/executor-admission.d.ts +1 -0
  77. package/dist/executor-admission.js +11 -15
  78. package/dist/executor-contract.d.ts +20 -0
  79. package/dist/executor-contract.js +48 -0
  80. package/dist/executor-result.js +24 -9
  81. package/dist/executors/quickjs-child.js +3 -4
  82. package/dist/executors/quickjs-runtime.js +147 -59
  83. package/dist/executors/quickjs.js +29 -35
  84. package/dist/favicon.js +1 -2
  85. package/dist/fix-prompt.js +1 -3
  86. package/dist/guest-runtime.js +188 -0
  87. package/dist/guest-types.d.ts +176 -0
  88. package/dist/guest-types.js +1 -0
  89. package/dist/html-security.js +24 -0
  90. package/dist/identity.js +1 -3
  91. package/dist/inbound-credential.js +52 -0
  92. package/dist/index.d.ts +24 -256
  93. package/dist/index.js +65 -478
  94. package/dist/invocation-auth.js +69 -0
  95. package/dist/invocation.js +230 -73
  96. package/dist/json-schema.d.ts +1 -1
  97. package/dist/mcp-client-context.js +35 -0
  98. package/dist/mcp-result.js +11 -7
  99. package/dist/meta-output.js +76 -0
  100. package/dist/meta-tool-names.d.ts +2 -0
  101. package/dist/meta-tool-names.js +3 -0
  102. package/dist/meta-tools.js +285 -209
  103. package/dist/module-contracts.d.ts +8 -23
  104. package/dist/node.d.ts +0 -2
  105. package/dist/node.js +2 -2
  106. package/dist/oauth-callback-outcome.js +1 -3
  107. package/dist/oauth-handoff.js +117 -0
  108. package/dist/oauth-sealing.js +20 -0
  109. package/dist/operator-record.d.ts +137 -0
  110. package/dist/operator-record.js +420 -0
  111. package/dist/operator-ui/assets.js +31 -0
  112. package/dist/operator-ui/contract.d.ts +72 -0
  113. package/dist/operator-ui/contract.js +1 -0
  114. package/dist/operator-ui/fix-prompts.d.ts +18 -0
  115. package/dist/operator-ui/generated.js +5 -4
  116. package/dist/operator-ui/model.d.ts +12 -87
  117. package/dist/operator-ui/model.js +2 -9
  118. package/dist/operator-ui/setup-commands.js +1 -3
  119. package/dist/operator-ui/view.d.ts +323 -0
  120. package/dist/operator-ui/view.js +62 -189
  121. package/dist/page-styles.js +2 -3
  122. package/dist/program-source.js +14 -2
  123. package/dist/{exempt-writes.js → program-writes.js} +55 -18
  124. package/dist/provider.d.ts +142 -0
  125. package/dist/provider.js +187 -0
  126. package/dist/providers/_shared/google/result-size.js +57 -0
  127. package/dist/providers/_shared/google/service-account.d.ts +58 -0
  128. package/dist/providers/_shared/google/service-account.js +500 -0
  129. package/dist/providers/_shared/google/workspace.d.ts +276 -0
  130. package/dist/providers/_shared/google/workspace.js +518 -0
  131. package/dist/providers/{basecamp.d.ts → basecamp/index.d.ts} +6 -28
  132. package/dist/providers/basecamp/index.js +997 -0
  133. package/dist/providers/basecamp/skill.generated.js +9 -0
  134. package/dist/providers/{breeze.d.ts → breeze/index.d.ts} +2 -2
  135. package/dist/providers/{breeze.js → breeze/index.js} +184 -140
  136. package/dist/providers/breeze/skill.generated.js +9 -0
  137. package/dist/providers/{ccb.d.ts → ccb/index.d.ts} +2 -2
  138. package/dist/providers/{ccb.js → ccb/index.js} +271 -116
  139. package/dist/providers/ccb/skill.generated.js +9 -0
  140. package/dist/providers/{cloudflare.d.ts → cloudflare/index.d.ts} +8 -7
  141. package/dist/providers/{cloudflare.js → cloudflare/index.js} +171 -738
  142. package/dist/providers/cloudflare/skill.generated.js +10 -0
  143. package/dist/providers/docs/index.d.ts +54 -0
  144. package/dist/providers/docs/index.js +1237 -0
  145. package/dist/providers/docs/skill.generated.js +9 -0
  146. package/dist/providers/drive/index.d.ts +53 -0
  147. package/dist/providers/drive/index.js +1523 -0
  148. package/dist/providers/drive/skill.generated.js +9 -0
  149. package/dist/providers/forms/index.d.ts +54 -0
  150. package/dist/providers/forms/index.js +1217 -0
  151. package/dist/providers/forms/skill.generated.js +11 -0
  152. package/dist/providers/github/auth.d.ts +32 -0
  153. package/dist/providers/github/auth.js +361 -0
  154. package/dist/providers/github/hosted.js +218 -0
  155. package/dist/providers/github/index.d.ts +13 -0
  156. package/dist/providers/github/index.js +140 -0
  157. package/dist/providers/github/key.js +100 -0
  158. package/dist/providers/github/rest.js +321 -0
  159. package/dist/providers/github/scope.d.ts +29 -0
  160. package/dist/providers/github/scope.js +124 -0
  161. package/dist/providers/github/skill.generated.js +8 -0
  162. package/dist/providers/gmail/index.d.ts +51 -0
  163. package/dist/providers/gmail/index.js +1436 -0
  164. package/dist/providers/gmail/skill.generated.js +9 -0
  165. package/dist/providers/{linear.d.ts → linear/index.d.ts} +11 -14
  166. package/dist/providers/linear/index.js +352 -0
  167. package/dist/providers/linear/skill.generated.js +8 -0
  168. package/dist/providers/{mixpanel.d.ts → mixpanel/index.d.ts} +5 -10
  169. package/dist/providers/mixpanel/index.js +416 -0
  170. package/dist/providers/mixpanel/skill.generated.js +9 -0
  171. package/dist/providers/{notion.d.ts → notion/index.d.ts} +8 -8
  172. package/dist/providers/{notion.js → notion/index.js} +226 -239
  173. package/dist/providers/notion/skill.generated.js +10 -0
  174. package/dist/providers/{overflow.d.ts → overflow/index.d.ts} +2 -2
  175. package/dist/providers/{overflow.js → overflow/index.js} +74 -111
  176. package/dist/providers/overflow/skill.generated.js +8 -0
  177. package/dist/providers/{planning-center.d.ts → planning-center/index.d.ts} +2 -2
  178. package/dist/providers/{planning-center.js → planning-center/index.js} +264 -104
  179. package/dist/providers/planning-center/skill.generated.js +10 -0
  180. package/dist/providers/{revenuecat.d.ts → revenuecat/index.d.ts} +5 -10
  181. package/dist/providers/revenuecat/index.js +557 -0
  182. package/dist/providers/revenuecat/skill.generated.js +11 -0
  183. package/dist/providers/sheets/index.d.ts +54 -0
  184. package/dist/providers/sheets/index.js +1237 -0
  185. package/dist/providers/sheets/skill.generated.js +10 -0
  186. package/dist/providers/slides/index.d.ts +53 -0
  187. package/dist/providers/slides/index.js +2645 -0
  188. package/dist/providers/slides/skill.generated.js +9 -0
  189. package/dist/providers/{stripe.d.ts → stripe/index.d.ts} +5 -12
  190. package/dist/providers/stripe/index.js +266 -0
  191. package/dist/providers/stripe/skill.generated.js +11 -0
  192. package/dist/providers/{tithely.d.ts → tithely/index.d.ts} +2 -2
  193. package/dist/providers/{tithely.js → tithely/index.js} +60 -91
  194. package/dist/providers/tithely/skill.generated.js +8 -0
  195. package/dist/providers/{vercel.d.ts → vercel/index.d.ts} +8 -8
  196. package/dist/providers/vercel/index.js +1038 -0
  197. package/dist/providers/vercel/mcp-ownership.js +212 -0
  198. package/dist/providers/vercel/skill.generated.js +11 -0
  199. package/dist/registry.d.ts +108 -171
  200. package/dist/registry.js +513 -925
  201. package/dist/request-state.js +21 -0
  202. package/dist/resource-read.js +100 -0
  203. package/dist/result-shapes.js +17 -49
  204. package/dist/retired-toolkits.js +1 -1
  205. package/dist/routes/access-tokens.js +3 -6
  206. package/dist/routes/activity-context.js +21 -0
  207. package/dist/routes/activity-disclosure.js +40 -0
  208. package/dist/routes/activity.js +59 -21
  209. package/dist/routes/actor-labels.js +3 -50
  210. package/dist/routes/connect.js +221 -0
  211. package/dist/routes/credentials.js +15 -27
  212. package/dist/routes/mcp.js +356 -130
  213. package/dist/routes/oauth-client-metadata.js +15 -0
  214. package/dist/routes/oauth-management.js +45 -107
  215. package/dist/routes/oauth.js +110 -57
  216. package/dist/routes/operator.js +3 -3
  217. package/dist/routes/shared.d.ts +25 -64
  218. package/dist/routes/shared.js +160 -80
  219. package/dist/routes/skills.js +30 -0
  220. package/dist/routes/ui-config.js +225 -0
  221. package/dist/routes/ui-data.js +40 -35
  222. package/dist/routes/ui.js +66 -56
  223. package/dist/runtime/admission.js +4 -2
  224. package/dist/runtime/call-admission.js +3 -1
  225. package/dist/runtime/connector-scope.js +1 -4
  226. package/dist/runtime/run.js +10 -39
  227. package/dist/runtime/services.js +12 -117
  228. package/dist/runtime/shared-read.js +1 -3
  229. package/dist/runtime/storage.js +8 -1
  230. package/dist/sent-secrets.d.ts +52 -0
  231. package/dist/sent-secrets.js +474 -0
  232. package/dist/server.js +28 -71
  233. package/dist/skills.js +406 -174
  234. package/dist/sqlite.d.ts +48 -0
  235. package/dist/sqlite.js +166 -0
  236. package/dist/storage/keys.js +428 -0
  237. package/dist/storage/memory.js +7 -0
  238. package/dist/storage/sql.d.ts +66 -0
  239. package/dist/storage/sql.js +534 -0
  240. package/dist/timeout.js +4 -2
  241. package/dist/tool-name.js +17 -0
  242. package/dist/tool-safety.d.ts +9 -35
  243. package/dist/tool-safety.js +20 -40
  244. package/dist/types.d.ts +320 -54
  245. package/dist/types.js +0 -1
  246. package/dist/ui.d.ts +7 -19
  247. package/dist/ui.js +76 -90
  248. package/dist/url-safety.js +3 -6
  249. package/dist/usage-guide.js +137 -0
  250. package/dist/validate.d.ts +7 -0
  251. package/dist/validate.js +309 -47
  252. package/dist/version.d.ts +1 -7
  253. package/dist/version.js +3 -7
  254. package/dist/worker.d.ts +11 -0
  255. package/dist/worker.js +434 -0
  256. package/documentation/architecture.md +664 -231
  257. package/documentation/auth.md +936 -546
  258. package/documentation/code-mode.md +501 -312
  259. package/documentation/meta-tools.md +449 -200
  260. package/documentation/operator-tests.md +93 -0
  261. package/documentation/provider-migration-0.29.md +60 -0
  262. package/examples/worker/AGENTS.md +34 -12
  263. package/examples/worker/README.md +286 -255
  264. package/examples/worker/kv-to-d1.wrangler.jsonc +26 -0
  265. package/examples/worker/scripts/copy-kv-to-d1.mjs +162 -0
  266. package/examples/worker/src/connecta.config.ts +151 -0
  267. package/examples/worker/src/index.ts +14 -197
  268. package/examples/worker/wrangler.jsonc +15 -35
  269. package/package.json +120 -54
  270. package/templates/node/.dockerignore +1 -2
  271. package/templates/node/.env.example +20 -21
  272. package/templates/node/AGENTS.md +21 -17
  273. package/templates/node/Dockerfile +3 -5
  274. package/templates/node/README.md +133 -58
  275. package/templates/node/docker-compose.yml +11 -12
  276. package/templates/node/package.json +4 -2
  277. package/templates/node/src/connecta.config.ts +119 -0
  278. package/templates/node/src/index.ts +9 -154
  279. package/templates/node/src/provision-token.ts +17 -0
  280. package/AGENTS.md +0 -170
  281. package/dist/artifacts/connector.d.ts +0 -58
  282. package/dist/artifacts/connector.js +0 -730
  283. package/dist/artifacts/document.js +0 -86
  284. package/dist/artifacts/guide.js +0 -140
  285. package/dist/artifacts/html-scan.js +0 -329
  286. package/dist/artifacts/json.js +0 -78
  287. package/dist/artifacts/kv-store.d.ts +0 -20
  288. package/dist/artifacts/kv-store.js +0 -140
  289. package/dist/artifacts/markdown.js +0 -478
  290. package/dist/artifacts/module.d.ts +0 -37
  291. package/dist/artifacts/module.js +0 -66
  292. package/dist/artifacts/operations.d.ts +0 -197
  293. package/dist/artifacts/operations.js +0 -1002
  294. package/dist/artifacts/refresh.d.ts +0 -55
  295. package/dist/artifacts/refresh.js +0 -236
  296. package/dist/artifacts/routes.js +0 -206
  297. package/dist/artifacts/types.d.ts +0 -214
  298. package/dist/artifacts/types.js +0 -22
  299. package/dist/artifacts/validate.d.ts +0 -62
  300. package/dist/artifacts/validate.js +0 -651
  301. package/dist/artifacts.d.ts +0 -6
  302. package/dist/artifacts.js +0 -9
  303. package/dist/auth/bearer.d.ts +0 -11
  304. package/dist/auth/bearer.js +0 -50
  305. package/dist/providers/basecamp.js +0 -445
  306. package/dist/providers/linear.js +0 -217
  307. package/dist/providers/mixpanel.js +0 -247
  308. package/dist/providers/revenuecat.js +0 -317
  309. package/dist/providers/stripe.js +0 -253
  310. package/dist/providers/vercel.js +0 -1253
  311. package/dist/storage/file.d.ts +0 -15
  312. package/dist/storage/file.js +0 -455
  313. package/ethos.md +0 -93
  314. package/examples/worker/src/cloudflare-kv.ts +0 -43
  315. package/examples/worker/src/d1-activity-row.ts +0 -155
  316. package/examples/worker/src/d1-activity.ts +0 -147
  317. package/examples/worker/src/d1-storage.ts +0 -138
  318. package/examples/worker/src/r2-artifact-blobs.ts +0 -29
  319. package/templates/node/src/file-activity.ts +0 -182
@@ -0,0 +1,9 @@
1
+ // Generated by scripts/generate-providers.mjs; do not edit.
2
+ export const skill = {
3
+ "content": ".breezechms.com (Breeze ChMS, now Tithely Church Management): people, tags, events, attendance, forms, volunteers, and giving.\n\nChurch purpose: \n\n## Sensitive data: reduce in code\n\nPeople records carry home addresses, phones, birthdates, and family ties, and\ngiving records reveal who gives and how much — religious affiliation by proxy.\nRead them inside `execute_code` and return only the counts, totals, or the\nfew fields the task needs. Never echo whole profiles or donor lists.\n\n## Ids and profile fields\n\n- Ids are numeric strings. Read them from a list tool; never guess one.\n- Events have two ids: an instance id (`list_events` `id`) for one\n occurrence, and a series `eventId`. Attendance, volunteers, and\n check-in take the instance id.\n- Person `details` are keyed by profile `fieldId`, not by name. Call\n `list_profile_fields` once and map ids to names in code. Multiple-choice\n values and `list_people` filters use option ids from the same call;\n join several with `-`.\n- `list_people` has no name search. List without details and match names\n in code, then `get_person` the hits.\n- Projections rename Breeze's snake_case fields to camelCase and drop photo\n paths and internal columns; `raw: true` returns Breeze's rows.\n\n## Pagination\n\n`list_people` pages by `cursor`: continue while `page.hasMore`. Breeze\nreports no total, so a full page sets `hasMore` and the next may be empty.\n`list_events` and `list_account_log` do not page: `truncated: true`\nmeans narrow the date range. Other lists return everything.\n\n## Giving\n\n`list_contributions` and `list_funds` call endpoints Breeze removed from\nits public reference in 2023 but still serves. They may change or vanish\nwithout notice; a failure there is not your argument's fault. Amounts are\ndecimal strings; `totalAmount` is an exact sum. Online gifts processed by\nTithe.ly arrive through its sync, batched per deposit, so the latest days\nmay be missing. Read the currency from `get_account_summary`.\n\n## Writes and the hatches\n\n- Every write, `add_person`, `assign_tag`, and `record_check_in`\n included, follows the routing in the `usage` skill. Fetch it with\n `skills({ name: \"usage\" })` for guest API and trust rules.\n Those three only add, and `add_person` never deduplicates.\n- `update_person` field values: text, date (M/D/YYYY), or option id in\n `response`; email, phone, address, and family_role values in `details`.\n- Every Breeze call is a GET, writes included, so the hatches split by\n endpoint. `breeze_api_get` admits only reviewed read endpoints and their\n documented parameters, such as `/tags/list_folders`,\n `/events/list_event`, `/events/attendance/eligible`, `/giving/view`,\n and `/pledges/list_campaigns`; it refuses anything else. Everything else\n — event, family, volunteer, and form writes, giving writes, check-out,\n undocumented parameters — is `breeze_api_mutate`. Paths are below\n `/api`; `*_json` values may be passed as objects.\n- `list_account_log` actions include person_created, person_updated,\n person_deleted, tag_assign, tag_unassign, event_created,\n attendance_deleted, form_entry_updated, contribution_added,\n contribution_updated, contribution_deleted, and batch_updated.\n\n## Rate limits\n\nBreeze publishes no limit and sends no rate headers; a third party reports\nabout 20 requests per minute. Keep loops sequential and prefer one list call\nover many single reads.\n",
4
+ "instructionsHeading": "Church instructions",
5
+ "fragments": {
6
+ "guide_0": ".breezechms.com (Breeze ChMS, now Tithely Church Management): people, tags, events, attendance, forms, volunteers, and giving.\n\nChurch purpose: ",
7
+ "guide_1": "\n\n## Sensitive data: reduce in code\n\nPeople records carry home addresses, phones, birthdates, and family ties, and\ngiving records reveal who gives and how much — religious affiliation by proxy.\nRead them inside `execute_code` and return only the counts, totals, or the\nfew fields the task needs. Never echo whole profiles or donor lists.\n\n## Ids and profile fields\n\n- Ids are numeric strings. Read them from a list tool; never guess one.\n- Events have two ids: an instance id (`list_events` `id`) for one\n occurrence, and a series `eventId`. Attendance, volunteers, and\n check-in take the instance id.\n- Person `details` are keyed by profile `fieldId`, not by name. Call\n `list_profile_fields` once and map ids to names in code. Multiple-choice\n values and `list_people` filters use option ids from the same call;\n join several with `-`.\n- `list_people` has no name search. List without details and match names\n in code, then `get_person` the hits.\n- Projections rename Breeze's snake_case fields to camelCase and drop photo\n paths and internal columns; `raw: true` returns Breeze's rows.\n\n## Pagination\n\n`list_people` pages by `cursor`: continue while `page.hasMore`. Breeze\nreports no total, so a full page sets `hasMore` and the next may be empty.\n`list_events` and `list_account_log` do not page: `truncated: true`\nmeans narrow the date range. Other lists return everything.\n\n## Giving\n\n`list_contributions` and `list_funds` call endpoints Breeze removed from\nits public reference in 2023 but still serves. They may change or vanish\nwithout notice; a failure there is not your argument's fault. Amounts are\ndecimal strings; `totalAmount` is an exact sum. Online gifts processed by\nTithe.ly arrive through its sync, batched per deposit, so the latest days\nmay be missing. Read the currency from `get_account_summary`.\n\n## Writes and the hatches\n\n- Every write, `add_person`, `assign_tag`, and `record_check_in`\n included, follows the routing in the `usage` skill. Fetch it with\n `skills({ name: \"usage\" })` for guest API and trust rules.\n Those three only add, and `add_person` never deduplicates.\n- `update_person` field values: text, date (M/D/YYYY), or option id in\n `response`; email, phone, address, and family_role values in `details`.\n- Every Breeze call is a GET, writes included, so the hatches split by\n endpoint. `breeze_api_get` admits only reviewed read endpoints and their\n documented parameters, such as `/tags/list_folders`,\n `/events/list_event`, `/events/attendance/eligible`, `/giving/view`,\n and `/pledges/list_campaigns`; it refuses anything else. Everything else\n — event, family, volunteer, and form writes, giving writes, check-out,\n undocumented parameters — is `breeze_api_mutate`. Paths are below\n `/api`; `*_json` values may be passed as objects.\n- `list_account_log` actions include person_created, person_updated,\n person_deleted, tag_assign, tag_unassign, event_created,\n attendance_deleted, form_entry_updated, contribution_added,\n contribution_updated, contribution_deleted, and batch_updated.\n\n## Rate limits\n\nBreeze publishes no limit and sends no rate headers; a third party reports\nabout 20 requests per minute. Keep loops sequential and prefer one list call\nover many single reads.\n"
8
+ }
9
+ };
@@ -1,4 +1,4 @@
1
- import type { Connector, ConnectorCallAdmissionPolicy } from "../types.js";
1
+ import type { ConnectorCallAdmissionPolicy } from "../../types.js";
2
2
  /** CCB's v2 media type. The API and its token endpoint both require it. */
3
3
  export declare const CCB_MEDIA_TYPE = "application/vnd.ccbchurch.v2+json";
4
4
  /**
@@ -100,4 +100,4 @@ export interface CcbOptions {
100
100
  maxResultBytes?: number;
101
101
  }
102
102
  /** A maintained Church Community Builder (Pushpay ChMS) v2 connection. */
103
- export declare function ccb(id: string, options: CcbOptions): Connector;
103
+ export declare const ccb: import("../../provider.js").ProviderFactory<CcbOptions>;
@@ -1,3 +1,4 @@
1
+ import { skill } from "./skill.generated.js";
1
2
  /**
2
3
  * Church Community Builder — sold today as Pushpay ChMS — through its v2 JSON
3
4
  * REST API, hand-written over `api()`'s downstream OAuth grant.
@@ -22,16 +23,19 @@
22
23
  * pledges, scheduled gifts, and financial settings, and that is all this
23
24
  * connector reaches.
24
25
  *
25
- * Drift is handled the Vercel way: `scripts/drift/ccb-endpoints.json` records
26
+ * Drift is handled the Vercel way: `src/providers/ccb/drift.json` records
26
27
  * every endpoint a named tool touches, and
27
28
  * `npm run providers:check -- --provider ccb` compares those rows with the
28
29
  * published, credential-free OpenAPI document at
29
30
  * https://docs.pushpay.io/chms-v2/openapi/chms-api-specs.json.
30
31
  */
31
- import { api } from "../connectors/api.js";
32
- import { defined } from "../connectors/api-connector.js";
33
- import { guardedFetch, oauthBearer, retryAfterMs, } from "../connectors/guarded-fetch.js";
34
- import { ConnectorCallError } from "../errors.js";
32
+ import { api } from "../../connectors/api.js";
33
+ import { defined } from "../../connectors/api-connector.js";
34
+ import { guardedFetch, oauthBearer, retryAfterMs, } from "../../connectors/guarded-fetch.js";
35
+ import { ConnectorCallError } from "../../errors.js";
36
+ import { keys, optionsOf } from "../../config-schema.js";
37
+ import { CALL_ADMISSION } from "../../connectors/option-shapes.js";
38
+ import { asProviderFactory } from "../../provider.js";
35
39
  /** CCB's v2 media type. The API and its token endpoint both require it. */
36
40
  export const CCB_MEDIA_TYPE = "application/vnd.ccbchurch.v2+json";
37
41
  /**
@@ -138,9 +142,7 @@ const CCB_ADMISSION = {
138
142
  ],
139
143
  };
140
144
  function asRecord(value) {
141
- return value && typeof value === "object" && !Array.isArray(value)
142
- ? value
143
- : {};
145
+ return value && typeof value === "object" && !Array.isArray(value) ? value : {};
144
146
  }
145
147
  function asArray(value) {
146
148
  return Array.isArray(value) ? value : [];
@@ -179,9 +181,7 @@ const NAMED_ENDPOINTS = {
179
181
  list_schedules: "GET /scheduling/categories/{id}/schedules",
180
182
  list_individual_assignments: "GET /individuals/{id}/assignments",
181
183
  list_individual_notes: "GET /individuals/{id}/notes",
182
- get_giving_metrics: (args) => args["familyId"] !== undefined
183
- ? "GET /families/{id}/metrics/giving"
184
- : "GET /individuals/{id}/metrics/giving",
184
+ get_giving_metrics: (args) => args["familyId"] !== undefined ? "GET /families/{id}/metrics/giving" : "GET /individuals/{id}/metrics/giving",
185
185
  list_individual_pledges: "GET /individuals/{id}/pledges",
186
186
  ccb_api_search: (args) => `POST /search/${typeof args["domain"] === "string" ? args["domain"] : "?"}/results`,
187
187
  };
@@ -208,17 +208,16 @@ function endpointPartition(toolName, raw) {
208
208
  else if (named)
209
209
  key = named(args);
210
210
  else {
211
- const method = toolName === "ccb_api_get"
212
- ? "GET"
213
- : typeof args["method"] === "string"
214
- ? args["method"]
215
- : "?";
211
+ const method = toolName === "ccb_api_get" ? "GET" : typeof args["method"] === "string" ? args["method"] : "?";
216
212
  const path = typeof args["path"] === "string" ? args["path"] : "";
217
213
  key = `${method} ${pathTemplate(path)}`;
218
214
  }
219
215
  // ASCII-only after templating in every realistic case; the slice keeps an
220
216
  // absurd path inside the admission controller's 128-byte key limit anyway.
221
- return [...key].filter((c) => c.charCodeAt(0) < 128).join("").slice(0, MAX_PARTITION_KEY_CHARS);
217
+ return [...key]
218
+ .filter((c) => c.charCodeAt(0) < 128)
219
+ .join("")
220
+ .slice(0, MAX_PARTITION_KEY_CHARS);
222
221
  }
223
222
  // ---------------------------------------------------------------------------
224
223
  // Transport and typed failures
@@ -278,7 +277,7 @@ function ccbFailure(status, headers, payload) {
278
277
  return new ConnectorCallError("auth_required", `${detail} CCB rejected the connection's access token. Call authorize_connector for this connector, then retry.`);
279
278
  }
280
279
  if (status === 403) {
281
- return new ConnectorCallError("connector_call_failed", `${detail} The grant lacks this endpoint's scope, or (Identity Auth) the signed-in person lacks the permission in CCB. Re-authorizing alone will not fix it.`, { retryable: false });
280
+ return new ConnectorCallError("provider_permission_denied", `${detail} The grant lacks this endpoint's scope, or (Identity Auth) the signed-in person lacks the permission in CCB. Ask the CCB administrator to grant this endpoint's scope or the signed-in person's permission. Re-authorizing alone will not fix it.`, { retryable: false });
282
281
  }
283
282
  if (status === 404) {
284
283
  return new ConnectorCallError("not_found", `${detail} Re-read the id from its list tool; CCB reports a permission gap as 403, so this record does not exist.`);
@@ -310,7 +309,9 @@ async function callCcb(send, request, ctx) {
310
309
  throw ccbFailure(response.status, response.headers, "value" in parsed ? parsed.value : undefined);
311
310
  }
312
311
  if (!("value" in parsed)) {
313
- throw new ConnectorCallError("connector_call_failed", "CCB returned a successful response that is not JSON.", { retryable: false });
312
+ throw new ConnectorCallError("connector_call_failed", "CCB returned a successful response that is not JSON.", {
313
+ retryable: false,
314
+ });
314
315
  }
315
316
  return { body: parsed.value, headers: response.headers };
316
317
  });
@@ -569,9 +570,7 @@ function projectProcess(value) {
569
570
  ownerId: row["owner_id"],
570
571
  hidden: row["hidden"],
571
572
  archived: row["archived"],
572
- managers: Array.isArray(row["process_managers"])
573
- ? row["process_managers"].map(ref).filter(Boolean)
574
- : undefined,
573
+ managers: Array.isArray(row["process_managers"]) ? row["process_managers"].map(ref).filter(Boolean) : undefined,
575
574
  });
576
575
  }
577
576
  function projectQueue(value) {
@@ -732,88 +731,220 @@ function input(properties, required = []) {
732
731
  }
733
732
  const PHONES = obj({ mobile: STR, home: STR, work: STR });
734
733
  const PERSON_SCHEMA = obj({
735
- id: INT, name: STR, firstName: STR, lastName: STR, email: STR, phones: PHONES,
736
- birthday: STR, familyId: INT, familyPosition: STR, campusId: INT,
737
- membershipTypeId: INT, active: BOOL, deceased: STR,
734
+ id: INT,
735
+ name: STR,
736
+ firstName: STR,
737
+ lastName: STR,
738
+ email: STR,
739
+ phones: PHONES,
740
+ birthday: STR,
741
+ familyId: INT,
742
+ familyPosition: STR,
743
+ campusId: INT,
744
+ membershipTypeId: INT,
745
+ active: BOOL,
746
+ deceased: STR,
738
747
  });
739
748
  const ADDRESS = obj({ street: STR, city: STR, state: STR, zip: STR, country: STR });
740
749
  const INDIVIDUAL_SCHEMA = obj({
741
750
  ...PERSON_SCHEMA.properties,
742
- gender: STR, maritalStatus: STR, homeAddress: ADDRESS, mailingAddress: ADDRESS,
743
- campusName: STR, membershipTypeName: STR, membershipDate: STR, baptized: BOOL,
744
- lastAttendedDate: STR, listed: BOOL, customFields: { type: "object" },
751
+ gender: STR,
752
+ maritalStatus: STR,
753
+ homeAddress: ADDRESS,
754
+ mailingAddress: ADDRESS,
755
+ campusName: STR,
756
+ membershipTypeName: STR,
757
+ membershipDate: STR,
758
+ baptized: BOOL,
759
+ lastAttendedDate: STR,
760
+ listed: BOOL,
761
+ customFields: { type: "object" },
762
+ });
763
+ const FAMILY_SCHEMA = obj({
764
+ id: INT,
765
+ lastName: STR,
766
+ address: ADDRESS,
767
+ members: { type: "array", items: PERSON_SCHEMA },
745
768
  });
746
- const FAMILY_SCHEMA = obj({ id: INT, lastName: STR, address: ADDRESS, members: { type: "array", items: PERSON_SCHEMA } });
747
769
  const REF = obj({ id: INT, name: STR });
748
770
  const GROUP_SCHEMA = obj({
749
- id: INT, name: STR, campusId: INT, inactive: BOOL, groupType: STR,
750
- interactionType: STR, membershipType: STR, mainLeader: REF, departmentId: INT,
771
+ id: INT,
772
+ name: STR,
773
+ campusId: INT,
774
+ inactive: BOOL,
775
+ groupType: STR,
776
+ interactionType: STR,
777
+ membershipType: STR,
778
+ mainLeader: REF,
779
+ departmentId: INT,
751
780
  });
752
781
  const GROUP_DETAIL_SCHEMA = obj({
753
782
  ...GROUP_SCHEMA.properties,
754
- description: STR, memberCount: INT, childcare: BOOL, listed: BOOL, full: BOOL,
755
- meetDay: STR, meetTime: STR, area: STR, address: ADDRESS,
783
+ description: STR,
784
+ memberCount: INT,
785
+ childcare: BOOL,
786
+ listed: BOOL,
787
+ full: BOOL,
788
+ meetDay: STR,
789
+ meetTime: STR,
790
+ area: STR,
791
+ address: ADDRESS,
756
792
  });
757
793
  const MEMBERSHIP_SCHEMA = obj({
758
- groupId: INT, individualId: INT, status: STR, dateAdded: STR, name: STR, email: STR,
759
- phones: PHONES, groupName: STR, groupType: STR, groupInactive: BOOL,
794
+ groupId: INT,
795
+ individualId: INT,
796
+ status: STR,
797
+ dateAdded: STR,
798
+ name: STR,
799
+ email: STR,
800
+ phones: PHONES,
801
+ groupName: STR,
802
+ groupType: STR,
803
+ groupInactive: BOOL,
760
804
  });
761
805
  const OCCURRENCE_SCHEMA = obj({
762
- eventId: INT, occurrence: STR, start: STR, end: STR, name: STR, campusId: INT,
763
- recurs: BOOL, groupId: INT, groupName: STR,
806
+ eventId: INT,
807
+ occurrence: STR,
808
+ start: STR,
809
+ end: STR,
810
+ name: STR,
811
+ campusId: INT,
812
+ recurs: BOOL,
813
+ groupId: INT,
814
+ groupName: STR,
764
815
  });
765
816
  const EVENT_SCHEMA = obj({
766
- id: INT, name: STR, description: STR, campusId: INT, start: STR, end: STR,
767
- recurs: BOOL, recurEndDate: STR, approvalStatus: STR, address: ADDRESS,
768
- guestCounts: { type: "object" }, group: REF,
817
+ id: INT,
818
+ name: STR,
819
+ description: STR,
820
+ campusId: INT,
821
+ start: STR,
822
+ end: STR,
823
+ recurs: BOOL,
824
+ recurEndDate: STR,
825
+ approvalStatus: STR,
826
+ address: ADDRESS,
827
+ guestCounts: { type: "object" },
828
+ group: REF,
769
829
  attendance: obj({ status: STR, totalAttendance: INT, visitors: INT }),
770
830
  });
771
831
  const ATTENDANCE_SCHEMA = obj({
772
- eventId: INT, occurrence: STR, status: STR, totalAttendance: INT, visitors: INT, topic: STR,
832
+ eventId: INT,
833
+ occurrence: STR,
834
+ status: STR,
835
+ totalAttendance: INT,
836
+ visitors: INT,
837
+ topic: STR,
773
838
  });
774
839
  const ATTENDEE_SCHEMA = obj({ individualId: INT, name: STR, familyId: INT, occurrenceDate: STR });
775
840
  const FORM_SCHEMA = obj({
776
- id: INT, title: STR, status: STR, campusId: INT, start: STR, end: STR, public: BOOL, url: STR,
841
+ id: INT,
842
+ title: STR,
843
+ status: STR,
844
+ campusId: INT,
845
+ start: STR,
846
+ end: STR,
847
+ public: BOOL,
848
+ url: STR,
777
849
  });
778
850
  const RESPONSE_SCHEMA = obj({
779
- id: INT, formId: INT, individualId: INT, created: STR, paymentStatus: STR,
851
+ id: INT,
852
+ formId: INT,
853
+ individualId: INT,
854
+ created: STR,
855
+ paymentStatus: STR,
780
856
  answers: { type: "array", items: obj({ questionId: INT, answer: STR }) },
781
857
  });
782
858
  const PROCESS_SCHEMA = obj({
783
- id: INT, name: STR, campusId: INT, ownerId: INT, hidden: BOOL, archived: BOOL,
859
+ id: INT,
860
+ name: STR,
861
+ campusId: INT,
862
+ ownerId: INT,
863
+ hidden: BOOL,
864
+ archived: BOOL,
784
865
  managers: { type: "array", items: REF },
785
866
  });
786
867
  const QUEUE_SCHEMA = obj({
787
- id: INT, name: STR, processId: INT, processName: STR, description: STR,
788
- assignedCount: INT, unassignedCount: INT,
868
+ id: INT,
869
+ name: STR,
870
+ processId: INT,
871
+ processName: STR,
872
+ description: STR,
873
+ assignedCount: INT,
874
+ unassignedCount: INT,
789
875
  });
790
876
  const QUEUE_INDIVIDUAL_SCHEMA = obj({
791
- queueIndividualId: INT, queueId: INT, queueName: STR, processId: INT, processName: STR,
792
- individualId: INT, name: STR, status: STR, due: STR, created: STR, completed: STR,
877
+ queueIndividualId: INT,
878
+ queueId: INT,
879
+ queueName: STR,
880
+ processId: INT,
881
+ processName: STR,
882
+ individualId: INT,
883
+ name: STR,
884
+ status: STR,
885
+ due: STR,
886
+ created: STR,
887
+ completed: STR,
793
888
  });
794
889
  const CATEGORY_SCHEMA = obj({
795
- id: INT, name: STR, campus: REF, organizer: REF, archived: BOOL,
890
+ id: INT,
891
+ name: STR,
892
+ campus: REF,
893
+ organizer: REF,
894
+ archived: BOOL,
796
895
  teams: { type: "array", items: REF },
797
896
  });
798
897
  const SCHEDULE_SCHEMA = obj({
799
- id: INT, categoryId: INT, name: STR, start: STR, end: STR, needed: INT,
898
+ id: INT,
899
+ categoryId: INT,
900
+ name: STR,
901
+ start: STR,
902
+ end: STR,
903
+ needed: INT,
800
904
  events: { type: "array", items: obj({ id: INT, name: STR, start: STR, end: STR }) },
801
905
  metrics: { type: "object" },
802
906
  });
803
907
  const ASSIGNMENT_SCHEMA = obj({
804
- id: INT, categoryId: INT, scheduleId: INT, eventId: INT, eventPositionId: INT,
805
- status: STR, statusReason: STR, dateNotified: STR, individualId: INT, name: STR,
908
+ id: INT,
909
+ categoryId: INT,
910
+ scheduleId: INT,
911
+ eventId: INT,
912
+ eventPositionId: INT,
913
+ status: STR,
914
+ statusReason: STR,
915
+ dateNotified: STR,
916
+ individualId: INT,
917
+ name: STR,
806
918
  });
807
919
  const NOTE_SCHEMA = obj({
808
- id: INT, individualId: INT, note: STR, date: STR, sharingLevel: STR,
809
- context: STR, contextId: INT, creator: REF,
920
+ id: INT,
921
+ individualId: INT,
922
+ note: STR,
923
+ date: STR,
924
+ sharingLevel: STR,
925
+ context: STR,
926
+ contextId: INT,
927
+ creator: REF,
810
928
  });
811
929
  const PLEDGE_SCHEMA = obj({
812
- id: INT, campusId: INT, fund: STR, pledged: { type: "number" }, paid: { type: "number" },
813
- expected: { type: "number" }, total: { type: "number" }, frequency: STR, start: STR, end: STR,
930
+ id: INT,
931
+ campusId: INT,
932
+ fund: STR,
933
+ pledged: { type: "number" },
934
+ paid: { type: "number" },
935
+ expected: { type: "number" },
936
+ total: { type: "number" },
937
+ frequency: STR,
938
+ start: STR,
939
+ end: STR,
814
940
  });
815
941
  const ME_SCHEMA = obj({
816
- id: INT, name: STR, email: STR, username: STR, familyId: INT, campusId: INT,
942
+ id: INT,
943
+ name: STR,
944
+ email: STR,
945
+ username: STR,
946
+ familyId: INT,
947
+ campusId: INT,
817
948
  userTypes: { type: "array", items: STR },
818
949
  });
819
950
  /** Domains with a `POST /search/{domain}/results` endpoint in the v2 spec. */
@@ -952,10 +1083,19 @@ function tools(send, defaultPerPage, writable) {
952
1083
  description: "Find CCB individuals by partial name, phone, or email. Returns lean profiles with family and campus ids; not the advanced search.",
953
1084
  annotations: readOnly,
954
1085
  inputSchema: input({
955
- query: { type: "string", minLength: 1, maxLength: 200, description: "Partial name, phone number, or email. Omit to page everyone." },
1086
+ query: {
1087
+ type: "string",
1088
+ minLength: 1,
1089
+ maxLength: 200,
1090
+ description: "Partial name, phone number, or email. Omit to page everyone.",
1091
+ },
956
1092
  includeInactive: { type: "boolean", description: "Include inactive individuals." },
957
1093
  includeDeceased: { type: "boolean", description: "Include deceased individuals." },
958
- campusScope: { type: "string", enum: ["all", "current", "other"], description: "Campuses to search relative to the connection's own." },
1094
+ campusScope: {
1095
+ type: "string",
1096
+ enum: ["all", "current", "other"],
1097
+ description: "Campuses to search relative to the connection's own.",
1098
+ },
959
1099
  page: PAGE,
960
1100
  perPage,
961
1101
  raw: RAW,
@@ -972,7 +1112,9 @@ function tools(send, defaultPerPage, writable) {
972
1112
  name: "get_individual",
973
1113
  description: "Get one CCB individual's profile: contact, addresses, membership, and custom fields. CCB allows one call a second; prefer list_individuals for many people.",
974
1114
  annotations: readOnly,
975
- inputSchema: input({ individualId: idProperty("Individual id from list_individuals."), raw: RAW }, ["individualId"]),
1115
+ inputSchema: input({ individualId: idProperty("Individual id from list_individuals."), raw: RAW }, [
1116
+ "individualId",
1117
+ ]),
976
1118
  outputSchema: INDIVIDUAL_SCHEMA,
977
1119
  handler: (args, ctx) => one(`/individuals/${id(args["individualId"])}`, args, ctx, projectIndividual),
978
1120
  },
@@ -1076,7 +1218,11 @@ function tools(send, defaultPerPage, writable) {
1076
1218
  annotations: readOnly,
1077
1219
  inputSchema: input({
1078
1220
  name: { type: "string", minLength: 1, maxLength: 200, description: "Partial event name." },
1079
- range: { type: "string", enum: ["ALL", "PAST", "CURRENT", "FUTURE"], description: "Time range relative to now." },
1221
+ range: {
1222
+ type: "string",
1223
+ enum: ["ALL", "PAST", "CURRENT", "FUTURE"],
1224
+ description: "Time range relative to now.",
1225
+ },
1080
1226
  page: PAGE,
1081
1227
  perPage,
1082
1228
  raw: RAW,
@@ -1107,7 +1253,10 @@ function tools(send, defaultPerPage, writable) {
1107
1253
  name: "get_event_attendance",
1108
1254
  description: "Get one CCB event occurrence's attendance summary: met or not, totals, visitors, topic. Drops leader notes and prayer requests unless raw.",
1109
1255
  annotations: readOnly,
1110
- inputSchema: input({ eventId: idProperty("Event id from list_events."), occurrence: OCCURRENCE, raw: RAW }, ["eventId", "occurrence"]),
1256
+ inputSchema: input({ eventId: idProperty("Event id from list_events."), occurrence: OCCURRENCE, raw: RAW }, [
1257
+ "eventId",
1258
+ "occurrence",
1259
+ ]),
1111
1260
  outputSchema: ATTENDANCE_SCHEMA,
1112
1261
  handler: (args, ctx) => one(`/events/${id(args["eventId"])}/attendance/${compactDate(args["occurrence"])}`, args, ctx, projectAttendance),
1113
1262
  },
@@ -1125,7 +1274,11 @@ function tools(send, defaultPerPage, writable) {
1125
1274
  annotations: readOnly,
1126
1275
  inputSchema: input({
1127
1276
  title: { type: "string", minLength: 1, maxLength: 200, description: "Partial form title." },
1128
- status: { type: "string", enum: ["ACTIVE", "SCHEDULED", "UNPUBLISHED", "EXPIRED", "ARCHIVED"], description: "Form status." },
1277
+ status: {
1278
+ type: "string",
1279
+ enum: ["ACTIVE", "SCHEDULED", "UNPUBLISHED", "EXPIRED", "ARCHIVED"],
1280
+ description: "Form status.",
1281
+ },
1129
1282
  campusId: idProperty("Only forms at this campus."),
1130
1283
  page: PAGE,
1131
1284
  perPage,
@@ -1187,7 +1340,11 @@ function tools(send, defaultPerPage, writable) {
1187
1340
  description: "List people in CCB process queues the connection can see, by status or assignment. CCB offers no per-queue filter here; filter on queueId.",
1188
1341
  annotations: readOnly,
1189
1342
  inputSchema: input({
1190
- status: { type: "string", enum: ["NOT_STARTED", "WAITING", "IN_PROCESS", "DONE"], description: "Queue status." },
1343
+ status: {
1344
+ type: "string",
1345
+ enum: ["NOT_STARTED", "WAITING", "IN_PROCESS", "DONE"],
1346
+ description: "Queue status.",
1347
+ },
1191
1348
  assignment: { type: "string", enum: ["ASSIGNED_TO_ME", "UNASSIGNED"], description: "Omit for both." },
1192
1349
  page: PAGE,
1193
1350
  perPage,
@@ -1205,12 +1362,20 @@ function tools(send, defaultPerPage, writable) {
1205
1362
  annotations: readOnly,
1206
1363
  inputSchema: input({
1207
1364
  search: { type: "string", minLength: 1, maxLength: 200, description: "Category name search." },
1208
- status: { type: "string", enum: ["ACTIVE", "ARCHIVED", "ACTIVE_AND_ARCHIVED"], description: "Defaults to CCB's own (active)." },
1365
+ status: {
1366
+ type: "string",
1367
+ enum: ["ACTIVE", "ARCHIVED", "ACTIVE_AND_ARCHIVED"],
1368
+ description: "Defaults to CCB's own (active).",
1369
+ },
1209
1370
  raw: RAW,
1210
1371
  }),
1211
1372
  outputSchema: rowsOutput("categories", CATEGORY_SCHEMA),
1212
1373
  handler: async (args, ctx) => {
1213
- const { body } = await callCcb(send, { method: "GET", path: "/scheduling/categories", query: { search_term: args["search"], status: args["status"] } }, ctx);
1374
+ const { body } = await callCcb(send, {
1375
+ method: "GET",
1376
+ path: "/scheduling/categories",
1377
+ query: { search_term: args["search"], status: args["status"] },
1378
+ }, ctx);
1214
1379
  const rows = Array.isArray(body) ? body : body && typeof body === "object" ? [body] : [];
1215
1380
  return { categories: args["raw"] === true ? rows : rows.map(projectCategory) };
1216
1381
  },
@@ -1261,7 +1426,11 @@ function tools(send, defaultPerPage, writable) {
1261
1426
  annotations: readOnly,
1262
1427
  inputSchema: input({
1263
1428
  individualId: idProperty("Individual id."),
1264
- context: { type: "string", enum: ["GROUP", "DEPARTMENT", "PROCESS_QUEUE", "GENERAL"], description: "Only notes in this context." },
1429
+ context: {
1430
+ type: "string",
1431
+ enum: ["GROUP", "DEPARTMENT", "PROCESS_QUEUE", "GENERAL"],
1432
+ description: "Only notes in this context.",
1433
+ },
1265
1434
  page: PAGE,
1266
1435
  perPage,
1267
1436
  raw: RAW,
@@ -1286,7 +1455,11 @@ function tools(send, defaultPerPage, writable) {
1286
1455
  outputSchema: obj({
1287
1456
  periods: {
1288
1457
  type: "array",
1289
- items: obj({ start: STR, count: INT, members: { type: "array", items: obj({ individualId: INT, count: INT }) } }),
1458
+ items: obj({
1459
+ start: STR,
1460
+ count: INT,
1461
+ members: { type: "array", items: obj({ individualId: INT, count: INT }) },
1462
+ }),
1290
1463
  },
1291
1464
  }),
1292
1465
  handler: async (args, ctx) => {
@@ -1327,7 +1500,9 @@ function tools(send, defaultPerPage, writable) {
1327
1500
  name: "list_individual_pledges",
1328
1501
  description: "List one CCB individual's pledges: fund, pledged, paid, and expected amounts, and recurrence.",
1329
1502
  annotations: readOnly,
1330
- inputSchema: input({ individualId: idProperty("Individual id."), page: PAGE, perPage, raw: RAW }, ["individualId"]),
1503
+ inputSchema: input({ individualId: idProperty("Individual id."), page: PAGE, perPage, raw: RAW }, [
1504
+ "individualId",
1505
+ ]),
1331
1506
  outputSchema: listOutput("pledges", PLEDGE_SCHEMA),
1332
1507
  handler: (args, ctx) => list(`/individuals/${id(args["individualId"])}/pledges`, args, ctx, "pledges", projectPledge),
1333
1508
  },
@@ -1392,7 +1567,11 @@ function tools(send, defaultPerPage, writable) {
1392
1567
  description: "Call any CCB v2 JSON POST, PUT, PATCH, or DELETE endpoint. The approval-gated hatch for every write; no file uploads.",
1393
1568
  annotations: { readOnlyHint: false, destructiveHint: true },
1394
1569
  inputSchema: input({
1395
- method: { type: "string", enum: ["POST", "PUT", "PATCH", "DELETE"], description: "HTTP method the endpoint documents." },
1570
+ method: {
1571
+ type: "string",
1572
+ enum: ["POST", "PUT", "PATCH", "DELETE"],
1573
+ description: "HTTP method the endpoint documents.",
1574
+ },
1396
1575
  path: HATCH_PATH,
1397
1576
  query: QUERY,
1398
1577
  body: {
@@ -1430,52 +1609,9 @@ function usageGuide(purpose, environment, mode, scopes, writable, instructions)
1430
1609
  const extra = instructions?.trim();
1431
1610
  return `# Church Community Builder (Pushpay ChMS)
1432
1611
 
1433
- ${routingLine(environment, mode, writable)}: ${purpose}
1434
-
1435
- ## Resolve ids before acting
1436
-
1437
- - Every record is addressed by an integer id. Read it from a list tool and
1438
- pass it back; never guess one. \`list_individuals\` finds people by partial
1439
- name, phone, or email; \`familyId\`, \`groupId\`, \`eventId\`, form, process,
1440
- queue, and category ids come from their own list tools.
1441
- - Events are series with dated occurrences. \`list_events\` returns
1442
- \`eventId\` plus \`occurrence\`; the attendance tools need both.
1443
- - Campus and membership-type ids resolve through \`ccb_api_get\` on
1444
- \`/campuses\` and \`/church/membership_types\`.
1445
- ${mode === "identity" ? "- Results are what the signed-in person may see in CCB. A 403 means that person lacks the permission, not that the connection is broken.\n" : ""}
1446
- ## Sensitive data stays out of results
1447
-
1448
- Projections drop allergies, giving numbers and dates, attendance prayer
1449
- requests and leader notes, and form payment details; \`raw: true\` returns
1450
- CCB's full row. Notes, pledges, giving metrics, background checks, and
1451
- financial settings are pastoral or financial: read them inside
1452
- \`execute_code\` and return only the reduced answer the task needs.
1453
-
1454
- Giving in v2 is counts per period (\`get_giving_metrics\`), pledges, scheduled
1455
- gifts, and financial settings. Transactions, batches, and amounts per gift
1456
- live only in CCB's legacy v1 XML API, which this connector does not reach.
1457
-
1458
- ## Paging
1459
-
1460
- Lists take \`page\` (1-based) and \`perPage\` (25, 50, 75, or 100 only) and
1461
- return \`page.hasMore\`, \`page.nextPage\`, and \`page.total\`. Field names are
1462
- CCB's snake_case turned camelCase.
1463
-
1464
- ## Rate limits
1465
-
1466
- CCB allows each endpoint about one call a second after a burst of 60, per API
1467
- client. This connector keeps a per-runtime 60-per-minute window per endpoint
1468
- — an approximation, not an enforcement. \`get_individual\` (1/s),
1469
- \`list_schedules\` (1 per 2 s), and individuals advanced search (1 per 5 s)
1470
- allow no burst: page a list instead of looping a get, and space those calls.
1471
- A \`rate_limited\` failure carries CCB's wait.
1472
-
1473
- ## Raw access
1474
-
1475
- \`ccb_api_get\` reaches any GET path; \`ccb_api_search\` runs advanced searches,
1476
- which CCB serves as POST but are reads.${writable ? " `ccb_api_mutate` reaches every POST, PUT, PATCH, and DELETE and always needs approval." : " This connection is read-only, so it ships no write tool."} Paths are below the API origin, such as \`/church/membership_types\`.
1612
+ ${routingLine(environment, mode, writable)}: ${purpose}${skill.fragments.guide_0}${mode === "identity" ? "- Results are what the signed-in person may see in CCB. A 403 means that person lacks the permission, not that the connection is broken.\n" : ""}${skill.fragments.guide_1}${writable ? " `ccb_api_mutate` reaches every POST, PUT, PATCH, and DELETE and always needs approval." : " This connection is read-only, so it ships no write tool."} Paths are below the API origin, such as \`/church/membership_types\`.
1477
1613
  Granted scopes: ${scopes.join(" ")}. A call outside them fails with 403.
1478
- ${extra ? `\n## Church instructions\n\n${extra}\n` : ""}`;
1614
+ ${extra ? `\n## ${skill.instructionsHeading}\n\n${extra}\n` : ""}`;
1479
1615
  }
1480
1616
  // ---------------------------------------------------------------------------
1481
1617
  // Constructor
@@ -1513,8 +1649,27 @@ function defaultTitle(environment, mode, writable) {
1513
1649
  ];
1514
1650
  return `Pushpay ChMS (CCB)${qualifiers.length ? ` — ${qualifiers.join(", ")}` : ""}`;
1515
1651
  }
1652
+ /** The closed options ccb() accepts; see `assertKnownOptions`. */
1653
+ const CCB_OPTIONS = optionsOf()({
1654
+ ...keys("purpose", "title", "instructions", "environment", "mode", "clientId", "clientSecret", "access", "scopes", "subdomain", "defaultPerPage", "maxResultBytes"),
1655
+ callAdmission: CALL_ADMISSION,
1656
+ });
1516
1657
  /** A maintained Church Community Builder (Pushpay ChMS) v2 connection. */
1517
- export function ccb(id, options) {
1658
+ export const ccb = asProviderFactory({
1659
+ name: "ccb",
1660
+ title: "Church Community Builder",
1661
+ kind: "api",
1662
+ readme: "Church Community Builder",
1663
+ bundle: {
1664
+ "baselineGzip": 120479,
1665
+ "maxGzip": 180479,
1666
+ "note": "./providers/ccb starts at 120,479 B gzip: the hand-written surface plus api()'s static OAuth grant over the SDK's auth client, with no remoteMcp() transport. The cap uses the baseline + 60,000 B policy.",
1667
+ },
1668
+ skill,
1669
+ options: CCB_OPTIONS,
1670
+ create: ccbConnector,
1671
+ });
1672
+ function ccbConnector(id, options) {
1518
1673
  const purpose = typeof options.purpose === "string" ? options.purpose.trim() : "";
1519
1674
  if (!purpose)
1520
1675
  throw new Error("ccb() requires a non-empty church purpose.");
@@ -0,0 +1,9 @@
1
+ // Generated by scripts/generate-providers.mjs; do not edit.
2
+ export const skill = {
3
+ "content": "\n\n## Resolve ids before acting\n\n- Every record is addressed by an integer id. Read it from a list tool and\n pass it back; never guess one. `list_individuals` finds people by partial\n name, phone, or email; `familyId`, `groupId`, `eventId`, form, process,\n queue, and category ids come from their own list tools.\n- Events are series with dated occurrences. `list_events` returns\n `eventId` plus `occurrence`; the attendance tools need both.\n- Campus and membership-type ids resolve through `ccb_api_get` on\n `/campuses` and `/church/membership_types`.\n\n## Sensitive data stays out of results\n\nProjections drop allergies, giving numbers and dates, attendance prayer\nrequests and leader notes, and form payment details; `raw: true` returns\nCCB's full row. Notes, pledges, giving metrics, background checks, and\nfinancial settings are pastoral or financial: read them inside\n`execute_code` and return only the reduced answer the task needs.\n\nGiving in v2 is counts per period (`get_giving_metrics`), pledges, scheduled\ngifts, and financial settings. Transactions, batches, and amounts per gift\nlive only in CCB's legacy v1 XML API, which this connector does not reach.\n\n## Paging\n\nLists take `page` (1-based) and `perPage` (25, 50, 75, or 100 only) and\nreturn `page.hasMore`, `page.nextPage`, and `page.total`. Field names are\nCCB's snake_case turned camelCase.\n\n## Rate limits\n\nCCB allows each endpoint about one call a second after a burst of 60, per API\nclient. This connector keeps a per-runtime 60-per-minute window per endpoint\n— an approximation, not an enforcement. `get_individual` (1/s),\n`list_schedules` (1 per 2 s), and individuals advanced search (1 per 5 s)\nallow no burst: page a list instead of looping a get, and space those calls.\nA `rate_limited` failure carries CCB's wait.\n\n## Raw access\n\n`ccb_api_get` reaches any GET path; `ccb_api_search` runs advanced searches,\nwhich CCB serves as POST but are reads.",
4
+ "instructionsHeading": "Church instructions",
5
+ "fragments": {
6
+ "guide_0": "\n\n## Resolve ids before acting\n\n- Every record is addressed by an integer id. Read it from a list tool and\n pass it back; never guess one. `list_individuals` finds people by partial\n name, phone, or email; `familyId`, `groupId`, `eventId`, form, process,\n queue, and category ids come from their own list tools.\n- Events are series with dated occurrences. `list_events` returns\n `eventId` plus `occurrence`; the attendance tools need both.\n- Campus and membership-type ids resolve through `ccb_api_get` on\n `/campuses` and `/church/membership_types`.\n",
7
+ "guide_1": "\n## Sensitive data stays out of results\n\nProjections drop allergies, giving numbers and dates, attendance prayer\nrequests and leader notes, and form payment details; `raw: true` returns\nCCB's full row. Notes, pledges, giving metrics, background checks, and\nfinancial settings are pastoral or financial: read them inside\n`execute_code` and return only the reduced answer the task needs.\n\nGiving in v2 is counts per period (`get_giving_metrics`), pledges, scheduled\ngifts, and financial settings. Transactions, batches, and amounts per gift\nlive only in CCB's legacy v1 XML API, which this connector does not reach.\n\n## Paging\n\nLists take `page` (1-based) and `perPage` (25, 50, 75, or 100 only) and\nreturn `page.hasMore`, `page.nextPage`, and `page.total`. Field names are\nCCB's snake_case turned camelCase.\n\n## Rate limits\n\nCCB allows each endpoint about one call a second after a burst of 60, per API\nclient. This connector keeps a per-runtime 60-per-minute window per endpoint\n— an approximation, not an enforcement. `get_individual` (1/s),\n`list_schedules` (1 per 2 s), and individuals advanced search (1 per 5 s)\nallow no burst: page a list instead of looping a get, and space those calls.\nA `rate_limited` failure carries CCB's wait.\n\n## Raw access\n\n`ccb_api_get` reaches any GET path; `ccb_api_search` runs advanced searches,\nwhich CCB serves as POST but are reads."
8
+ }
9
+ };