@zackbart/connecta 0.28.1 → 0.30.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +855 -5
- package/README.md +125 -116
- package/bin/connecta.mjs +121 -139
- package/bin/meta-tool-names.d.mts +2 -0
- package/bin/meta-tool-names.mjs +9 -0
- package/bin/version.mjs +3 -0
- package/dist/access-tokens.js +53 -63
- package/dist/activity-request.js +8 -0
- package/dist/activity.d.ts +76 -42
- package/dist/activity.js +110 -42
- package/dist/argument-redaction.js +230 -0
- package/dist/auth/clerk-sdk/client.d.ts +65 -0
- package/dist/auth/clerk-sdk/client.js +5 -0
- package/dist/auth/clerk-sdk/generated.js +1845 -0
- package/dist/auth/clerk-transport.js +19 -0
- package/dist/auth/clerk.d.ts +17 -7
- package/dist/auth/clerk.js +189 -107
- package/dist/auth/cloudflare-access.js +25 -26
- package/dist/auth/downstream-client-metadata.d.ts +29 -0
- package/dist/auth/downstream-client-metadata.js +133 -0
- package/dist/auth/downstream-oauth.js +1584 -1580
- package/dist/auth/downstream-revocation.js +106 -0
- package/dist/auth/oauth-token-response.js +231 -0
- package/dist/auth/oauth-v2-migration.js +116 -0
- package/dist/auth/static-oauth.js +93 -71
- package/dist/auth-elicitation.js +288 -0
- package/dist/authorization-handoff.js +111 -0
- package/dist/branding.d.ts +8 -16
- package/dist/branding.js +26 -59
- package/dist/byte-read-response.js +39 -0
- package/dist/call-admission.js +12 -16
- package/dist/catalog-cache.js +739 -0
- package/dist/catalog-drift.d.ts +50 -15
- package/dist/catalog-drift.js +365 -128
- package/dist/catalog-fingerprint.js +2 -4
- package/dist/catalog-freshness.js +13 -0
- package/dist/catalog-limits.js +2 -2
- package/dist/catalog-service.js +409 -225
- package/dist/catalog.js +43 -84
- package/dist/concurrency.js +3 -4
- package/dist/config-defaults.d.ts +39 -0
- package/dist/config-defaults.js +46 -0
- package/dist/config-schema.d.ts +181 -0
- package/dist/config-schema.js +435 -0
- package/dist/config-value-sources.js +102 -0
- package/dist/config.d.ts +633 -0
- package/dist/config.js +508 -0
- package/dist/connector-access.d.ts +1 -0
- package/dist/connector-access.js +13 -15
- package/dist/connector-caller.d.ts +8 -0
- package/dist/connector-caller.js +15 -6
- package/dist/connector-scope.js +1 -1
- package/dist/connectors/api-connector.d.ts +59 -7
- package/dist/connectors/api-connector.js +106 -19
- package/dist/connectors/api.js +4 -1
- package/dist/connectors/guarded-fetch.d.ts +144 -0
- package/dist/connectors/guarded-fetch.js +87 -38
- package/dist/connectors/negotiation-cache.js +46 -0
- package/dist/connectors/option-shapes.js +27 -0
- package/dist/connectors/remote-mcp.d.ts +30 -4
- package/dist/connectors/remote-mcp.js +1774 -320
- package/dist/connectors/resource-uri.js +335 -0
- package/dist/credential-contract.d.ts +10 -0
- package/dist/credential-rules.js +1 -3
- package/dist/credential-url.js +108 -0
- package/dist/credentials.d.ts +6 -1
- package/dist/credentials.js +27 -18
- package/dist/d1.d.ts +130 -0
- package/dist/d1.js +290 -0
- package/dist/describe-config.d.ts +165 -0
- package/dist/describe-config.js +315 -0
- package/dist/described.js +106 -0
- package/dist/downstream-input-context.js +128 -0
- package/dist/downstream-input.js +325 -0
- package/dist/errors.d.ts +132 -31
- package/dist/errors.js +175 -87
- package/dist/execute.js +798 -318
- package/dist/executor-admission.d.ts +1 -0
- package/dist/executor-admission.js +11 -15
- package/dist/executor-contract.d.ts +20 -0
- package/dist/executor-contract.js +48 -0
- package/dist/executor-result.js +30 -13
- package/dist/executors/quickjs-child.js +15 -9
- package/dist/executors/quickjs-protocol.js +5 -6
- package/dist/executors/quickjs-runtime.js +152 -59
- package/dist/executors/quickjs.js +49 -39
- package/dist/favicon.js +1 -2
- package/dist/fix-prompt.js +1 -3
- package/dist/guest-runtime.js +238 -0
- package/dist/guest-types.d.ts +218 -0
- package/dist/guest-types.js +1 -0
- package/dist/html-security.js +24 -0
- package/dist/identity.js +1 -3
- package/dist/inbound-credential.js +52 -0
- package/dist/index.d.ts +24 -256
- package/dist/index.js +65 -478
- package/dist/invocation-auth.js +69 -0
- package/dist/invocation.js +262 -79
- package/dist/json-schema.d.ts +1 -1
- package/dist/mcp-client-context.js +35 -0
- package/dist/mcp-result.js +11 -7
- package/dist/meta-output.js +61 -0
- package/dist/meta-tool-names.d.ts +2 -0
- package/dist/meta-tool-names.js +3 -0
- package/dist/meta-tools.js +419 -272
- package/dist/module-contracts.d.ts +8 -23
- package/dist/node.d.ts +0 -2
- package/dist/node.js +2 -2
- package/dist/oauth-callback-outcome.js +1 -3
- package/dist/oauth-handoff.js +194 -0
- package/dist/oauth-sealing.js +20 -0
- package/dist/operator-record.d.ts +137 -0
- package/dist/operator-record.js +420 -0
- package/dist/operator-ui/assets.js +31 -0
- package/dist/operator-ui/contract.d.ts +72 -0
- package/dist/operator-ui/contract.js +1 -0
- package/dist/operator-ui/fix-prompts.d.ts +18 -0
- package/dist/operator-ui/generated.js +5 -4
- package/dist/operator-ui/model.d.ts +12 -87
- package/dist/operator-ui/model.js +2 -9
- package/dist/operator-ui/setup-commands.js +1 -3
- package/dist/operator-ui/view.d.ts +323 -0
- package/dist/operator-ui/view.js +62 -189
- package/dist/page-styles.js +2 -3
- package/dist/program-result.js +5 -0
- package/dist/program-source.js +14 -2
- package/dist/{exempt-writes.js → program-writes.js} +60 -19
- package/dist/provider.d.ts +142 -0
- package/dist/provider.js +187 -0
- package/dist/providers/_shared/google/result-size.js +57 -0
- package/dist/providers/_shared/google/service-account.d.ts +58 -0
- package/dist/providers/_shared/google/service-account.js +500 -0
- package/dist/providers/_shared/google/workspace.d.ts +276 -0
- package/dist/providers/_shared/google/workspace.js +518 -0
- package/dist/providers/_shared/request-token.js +83 -0
- package/dist/providers/{basecamp.d.ts → basecamp/index.d.ts} +6 -28
- package/dist/providers/basecamp/index.js +997 -0
- package/dist/providers/basecamp/skill.generated.js +9 -0
- package/dist/providers/{breeze.d.ts → breeze/index.d.ts} +2 -2
- package/dist/providers/{breeze.js → breeze/index.js} +184 -140
- package/dist/providers/breeze/skill.generated.js +9 -0
- package/dist/providers/{ccb.d.ts → ccb/index.d.ts} +2 -2
- package/dist/providers/{ccb.js → ccb/index.js} +271 -116
- package/dist/providers/ccb/skill.generated.js +9 -0
- package/dist/providers/{cloudflare.d.ts → cloudflare/index.d.ts} +8 -7
- package/dist/providers/{cloudflare.js → cloudflare/index.js} +171 -738
- package/dist/providers/cloudflare/skill.generated.js +10 -0
- package/dist/providers/docs/index.d.ts +54 -0
- package/dist/providers/docs/index.js +1237 -0
- package/dist/providers/docs/skill.generated.js +9 -0
- package/dist/providers/drive/index.d.ts +53 -0
- package/dist/providers/drive/index.js +1523 -0
- package/dist/providers/drive/skill.generated.js +9 -0
- package/dist/providers/forms/index.d.ts +54 -0
- package/dist/providers/forms/index.js +1217 -0
- package/dist/providers/forms/skill.generated.js +11 -0
- package/dist/providers/github/auth.d.ts +32 -0
- package/dist/providers/github/auth.js +361 -0
- package/dist/providers/github/hosted.js +218 -0
- package/dist/providers/github/index.d.ts +13 -0
- package/dist/providers/github/index.js +140 -0
- package/dist/providers/github/key.js +100 -0
- package/dist/providers/github/rest.js +321 -0
- package/dist/providers/github/scope.d.ts +29 -0
- package/dist/providers/github/scope.js +124 -0
- package/dist/providers/github/skill.generated.js +8 -0
- package/dist/providers/gmail/index.d.ts +51 -0
- package/dist/providers/gmail/index.js +1436 -0
- package/dist/providers/gmail/skill.generated.js +9 -0
- package/dist/providers/infisical/index.d.ts +7 -0
- package/dist/providers/infisical/index.js +713 -0
- package/dist/providers/infisical/skill.generated.js +8 -0
- package/dist/providers/{linear.d.ts → linear/index.d.ts} +11 -14
- package/dist/providers/linear/index.js +352 -0
- package/dist/providers/linear/skill.generated.js +8 -0
- package/dist/providers/{mixpanel.d.ts → mixpanel/index.d.ts} +5 -10
- package/dist/providers/mixpanel/index.js +416 -0
- package/dist/providers/mixpanel/skill.generated.js +9 -0
- package/dist/providers/{notion.d.ts → notion/index.d.ts} +8 -8
- package/dist/providers/{notion.js → notion/index.js} +226 -239
- package/dist/providers/notion/skill.generated.js +10 -0
- package/dist/providers/{overflow.d.ts → overflow/index.d.ts} +2 -2
- package/dist/providers/{overflow.js → overflow/index.js} +74 -111
- package/dist/providers/overflow/skill.generated.js +8 -0
- package/dist/providers/{planning-center.d.ts → planning-center/index.d.ts} +2 -2
- package/dist/providers/{planning-center.js → planning-center/index.js} +264 -104
- package/dist/providers/planning-center/skill.generated.js +10 -0
- package/dist/providers/{revenuecat.d.ts → revenuecat/index.d.ts} +5 -10
- package/dist/providers/revenuecat/index.js +557 -0
- package/dist/providers/revenuecat/skill.generated.js +11 -0
- package/dist/providers/sheets/index.d.ts +54 -0
- package/dist/providers/sheets/index.js +1237 -0
- package/dist/providers/sheets/skill.generated.js +10 -0
- package/dist/providers/slides/index.d.ts +53 -0
- package/dist/providers/slides/index.js +2645 -0
- package/dist/providers/slides/skill.generated.js +9 -0
- package/dist/providers/{stripe.d.ts → stripe/index.d.ts} +5 -12
- package/dist/providers/stripe/index.js +266 -0
- package/dist/providers/stripe/skill.generated.js +11 -0
- package/dist/providers/{tithely.d.ts → tithely/index.d.ts} +2 -2
- package/dist/providers/{tithely.js → tithely/index.js} +60 -91
- package/dist/providers/tithely/skill.generated.js +8 -0
- package/dist/providers/{vercel.d.ts → vercel/index.d.ts} +8 -8
- package/dist/providers/vercel/index.js +1038 -0
- package/dist/providers/vercel/mcp-ownership.js +212 -0
- package/dist/providers/vercel/skill.generated.js +11 -0
- package/dist/registry.d.ts +110 -171
- package/dist/registry.js +588 -927
- package/dist/request-state.js +21 -0
- package/dist/resource-read.js +103 -0
- package/dist/result-shapes.js +17 -49
- package/dist/retired-toolkits.js +1 -1
- package/dist/routes/access-tokens.js +3 -6
- package/dist/routes/activity-context.js +21 -0
- package/dist/routes/activity-disclosure.js +40 -0
- package/dist/routes/activity.js +59 -21
- package/dist/routes/actor-labels.js +3 -50
- package/dist/routes/connect.js +221 -0
- package/dist/routes/credentials.js +15 -27
- package/dist/routes/mcp.js +365 -130
- package/dist/routes/oauth-client-metadata.js +15 -0
- package/dist/routes/oauth-management.js +45 -107
- package/dist/routes/oauth.js +110 -57
- package/dist/routes/operator.js +3 -3
- package/dist/routes/shared.d.ts +25 -64
- package/dist/routes/shared.js +160 -80
- package/dist/routes/skills.js +30 -0
- package/dist/routes/ui-config.js +225 -0
- package/dist/routes/ui-data.js +40 -35
- package/dist/routes/ui.js +66 -56
- package/dist/runtime/admission.js +4 -2
- package/dist/runtime/call-admission.js +3 -1
- package/dist/runtime/connector-scope.js +1 -4
- package/dist/runtime/run.js +10 -39
- package/dist/runtime/services.js +12 -117
- package/dist/runtime/shared-read.js +1 -3
- package/dist/runtime/storage.js +8 -1
- package/dist/sent-secrets.d.ts +93 -0
- package/dist/sent-secrets.js +1013 -0
- package/dist/server.js +28 -71
- package/dist/skills.js +416 -174
- package/dist/sqlite.d.ts +48 -0
- package/dist/sqlite.js +181 -0
- package/dist/storage/keys.js +443 -0
- package/dist/storage/memory.js +16 -4
- package/dist/storage/sql.d.ts +66 -0
- package/dist/storage/sql.js +543 -0
- package/dist/timeout.js +4 -2
- package/dist/tool-name.js +17 -0
- package/dist/tool-safety.d.ts +9 -35
- package/dist/tool-safety.js +20 -40
- package/dist/types.d.ts +336 -56
- package/dist/types.js +0 -1
- package/dist/ui.d.ts +7 -19
- package/dist/ui.js +76 -90
- package/dist/url-safety.js +3 -6
- package/dist/usage-guide.js +146 -0
- package/dist/validate.d.ts +7 -0
- package/dist/validate.js +309 -47
- package/dist/version.d.ts +1 -7
- package/dist/version.js +3 -7
- package/dist/worker.d.ts +11 -0
- package/dist/worker.js +435 -0
- package/documentation/README.md +63 -0
- package/documentation/architecture.md +696 -231
- package/documentation/auth.md +1069 -546
- package/documentation/code-mode.md +662 -356
- package/documentation/deploying.md +146 -0
- package/documentation/integrating.md +159 -0
- package/documentation/meta-tools.md +570 -216
- package/documentation/operating.md +135 -0
- package/documentation/operator-tests.md +97 -0
- package/documentation/operator-ui.md +132 -0
- package/documentation/provider-migration-0.29.md +65 -0
- package/examples/worker/AGENTS.md +34 -12
- package/examples/worker/README.md +293 -255
- package/examples/worker/kv-to-d1.wrangler.jsonc +26 -0
- package/examples/worker/scripts/copy-kv-to-d1.mjs +162 -0
- package/examples/worker/src/connecta.config.ts +151 -0
- package/examples/worker/src/index.ts +14 -197
- package/examples/worker/wrangler.jsonc +15 -35
- package/package.json +126 -54
- package/templates/node/.dockerignore +1 -2
- package/templates/node/.env.example +20 -21
- package/templates/node/AGENTS.md +21 -17
- package/templates/node/Dockerfile +3 -5
- package/templates/node/README.md +140 -58
- package/templates/node/docker-compose.yml +11 -12
- package/templates/node/package.json +4 -2
- package/templates/node/src/connecta.config.ts +119 -0
- package/templates/node/src/index.ts +9 -154
- package/templates/node/src/provision-token.ts +17 -0
- package/AGENTS.md +0 -170
- package/dist/artifacts/connector.d.ts +0 -58
- package/dist/artifacts/connector.js +0 -730
- package/dist/artifacts/document.js +0 -86
- package/dist/artifacts/guide.js +0 -140
- package/dist/artifacts/html-scan.js +0 -329
- package/dist/artifacts/json.js +0 -78
- package/dist/artifacts/kv-store.d.ts +0 -20
- package/dist/artifacts/kv-store.js +0 -140
- package/dist/artifacts/markdown.js +0 -478
- package/dist/artifacts/module.d.ts +0 -37
- package/dist/artifacts/module.js +0 -66
- package/dist/artifacts/operations.d.ts +0 -197
- package/dist/artifacts/operations.js +0 -1002
- package/dist/artifacts/refresh.d.ts +0 -55
- package/dist/artifacts/refresh.js +0 -236
- package/dist/artifacts/routes.js +0 -206
- package/dist/artifacts/types.d.ts +0 -214
- package/dist/artifacts/types.js +0 -22
- package/dist/artifacts/validate.d.ts +0 -62
- package/dist/artifacts/validate.js +0 -651
- package/dist/artifacts.d.ts +0 -6
- package/dist/artifacts.js +0 -9
- package/dist/auth/bearer.d.ts +0 -11
- package/dist/auth/bearer.js +0 -50
- package/dist/providers/basecamp.js +0 -445
- package/dist/providers/linear.js +0 -217
- package/dist/providers/mixpanel.js +0 -247
- package/dist/providers/revenuecat.js +0 -317
- package/dist/providers/stripe.js +0 -253
- package/dist/providers/vercel.js +0 -1253
- package/dist/storage/file.d.ts +0 -15
- package/dist/storage/file.js +0 -455
- package/ethos.md +0 -93
- package/examples/worker/src/cloudflare-kv.ts +0 -43
- package/examples/worker/src/d1-activity-row.ts +0 -155
- package/examples/worker/src/d1-activity.ts +0 -147
- package/examples/worker/src/d1-storage.ts +0 -138
- package/examples/worker/src/r2-artifact-blobs.ts +0 -29
- 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": ". Basecamp's hosted server acts in the single account the grant was made for, and no tool takes an account id. Another account is another connector, never an argument.\n\n- Confirm the account before relying on it: `get_me` returns the signed-in person and a label naming the connected account. A record id from another account's URL answers \"not found\" here — read that as wrong connector, not missing data.\n- Basecamp's own reference notes are a read away: `get_basecamp_guide` with `topic` `concepts`, `finding-things`, `my-work`, `posting-and-mentions`, or `deleting-and-trash`. Read the topic before an unfamiliar sequence instead of guessing one.\n- Resolve ids before acting; never guess one. A Basecamp URL carries the account, project, and record ids, and `get_by_url` reads any link into those ids, the record, and where a reply goes. `search` finds records by text; `list_projects` then `get_project` returns a project's dock, whose tool ids (to-do set, message board, schedule, vault, card table, chat) the create tools take. People are ids from `list_people`, `list_project_people`, or `list_pingable_people`; mention someone by passing ids as `create_comment`'s `mentions`, not by writing markup.\n- Rich-text bodies (messages, documents, comments, cards, to-do descriptions) are HTML; a to-do's title and a chat line are plain text. Dates are `YYYY-MM-DD`.\n- Lists return up to `limit` items (100 by default). Continue with the `next_cursor` or `next_page` a result carries rather than raising the limit; `truncated: true` means the server cut a result to fit and says where to resume. The event feeds page by `position` instead. `get_card_table`, `get_document`, and the account-wide `list_everything_*` reads are large — reduce inside `execute_code` and return only the fields the question needs.\n- `trash_*` is restorable for 25 days; `delete_*`, `destroy_*`, and `remove_account_logo` are permanent. `update_cloud_file` and `update_google_document` are full replaces: an omitted title or description is erased, so read the record and resend every field you keep. `update_project_access` can invite people into the account.\n- Do not call `create_stream_ticket`: it mints a WebSocket credential for a client that holds a live connection, which a connecta call cannot. Poll `list_feed_events` instead. `get_event_inbox` serves agent accounts only; a person's grant gets `agents_only` back.\n- This connector's tool list is not a fixed set. Basecamp has not published this server and changes it without notice, and timesheets, gauges, hill charts, the Lineup, and check-ins depend on account features, so search this connector for what it actually exposes rather than assuming a tool exists.\n- Basecamp answers a rate limit with `429` and a `Retry-After` in seconds, and adjusts its limits dynamically. Back off for that long rather than retrying at once, and avoid speculative fan-out.\n- Treat every create, update, trash, delete, destroy, move, reposition, complete, pin, archive, enable, disable, watch, and mark operation as a write. For guest calls, classification, and routing, fetch `skills({ name: \"usage\" })`.\n- An `auth_required` failure means this connector's Basecamp authorization is missing or expired: run `authorize_connector` for this connector id, then retry the same call unchanged. A rejected argument, a permission gap, or a missing feature comes back in Basecamp's own words instead — read it rather than re-authorizing.\n",
|
|
4
|
+
"instructionsHeading": "Account instructions",
|
|
5
|
+
"fragments": {
|
|
6
|
+
"guide_0": ". Basecamp's hosted server acts in the single account the grant was made for, and no tool takes an account id. ",
|
|
7
|
+
"guide_1": " Another account is another connector, never an argument.\n\n- Confirm the account before relying on it: `get_me` returns the signed-in person and a label naming the connected account. A record id from another account's URL answers \"not found\" here — read that as wrong connector, not missing data.\n- Basecamp's own reference notes are a read away: `get_basecamp_guide` with `topic` `concepts`, `finding-things`, `my-work`, `posting-and-mentions`, or `deleting-and-trash`. Read the topic before an unfamiliar sequence instead of guessing one.\n- Resolve ids before acting; never guess one. A Basecamp URL carries the account, project, and record ids, and `get_by_url` reads any link into those ids, the record, and where a reply goes. `search` finds records by text; `list_projects` then `get_project` returns a project's dock, whose tool ids (to-do set, message board, schedule, vault, card table, chat) the create tools take. People are ids from `list_people`, `list_project_people`, or `list_pingable_people`; mention someone by passing ids as `create_comment`'s `mentions`, not by writing markup.\n- Rich-text bodies (messages, documents, comments, cards, to-do descriptions) are HTML; a to-do's title and a chat line are plain text. Dates are `YYYY-MM-DD`.\n- Lists return up to `limit` items (100 by default). Continue with the `next_cursor` or `next_page` a result carries rather than raising the limit; `truncated: true` means the server cut a result to fit and says where to resume. The event feeds page by `position` instead. `get_card_table`, `get_document`, and the account-wide `list_everything_*` reads are large — reduce inside `execute_code` and return only the fields the question needs.\n- `trash_*` is restorable for 25 days; `delete_*`, `destroy_*`, and `remove_account_logo` are permanent. `update_cloud_file` and `update_google_document` are full replaces: an omitted title or description is erased, so read the record and resend every field you keep. `update_project_access` can invite people into the account.\n- Do not call `create_stream_ticket`: it mints a WebSocket credential for a client that holds a live connection, which a connecta call cannot. Poll `list_feed_events` instead. `get_event_inbox` serves agent accounts only; a person's grant gets `agents_only` back.\n- This connector's tool list is not a fixed set. Basecamp has not published this server and changes it without notice, and timesheets, gauges, hill charts, the Lineup, and check-ins depend on account features, so search this connector for what it actually exposes rather than assuming a tool exists.\n- Basecamp answers a rate limit with `429` and a `Retry-After` in seconds, and adjusts its limits dynamically. Back off for that long rather than retrying at once, and avoid speculative fan-out.\n- Treat every create, update, trash, delete, destroy, move, reposition, complete, pin, archive, enable, disable, watch, and mark operation as a write. For guest calls, classification, and routing, fetch `skills({ name: \"usage\" })`.\n- An `auth_required` failure means this connector's Basecamp authorization is missing or expired: run `authorize_connector` for this connector id, then retry the same call unchanged. A rejected argument, a permission gap, or a missing feature comes back in Basecamp's own words instead — read it rather than re-authorizing.\n"
|
|
8
|
+
}
|
|
9
|
+
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { ConnectorCallAdmissionPolicy } from "../../types.js";
|
|
2
2
|
/** Every church's API lives at `https://<subdomain>.breezechms.com/api`. */
|
|
3
3
|
export declare const BREEZE_HOST_SUFFIX = ".breezechms.com";
|
|
4
4
|
export interface BreezeOptions {
|
|
@@ -31,4 +31,4 @@ export interface BreezeOptions {
|
|
|
31
31
|
defaultPageSize?: number;
|
|
32
32
|
}
|
|
33
33
|
/** A maintained Breeze ChMS connection for one church's subdomain. */
|
|
34
|
-
export declare
|
|
34
|
+
export declare const breeze: import("../../provider.js").ProviderFactory<BreezeOptions>;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { skill } from "./skill.generated.js";
|
|
1
2
|
/**
|
|
2
3
|
* Breeze ChMS — rebranded "Tithely Church Management" on 2025-11-11 — as a
|
|
3
4
|
* hand-written `api()` surface. No SDK exists worth wrapping: Breeze's API is
|
|
@@ -52,9 +53,12 @@
|
|
|
52
53
|
* distinct paths: the Tags section's "List People" points back at /people)
|
|
53
54
|
* plus the 2023 giving, funds, and pledges sections.
|
|
54
55
|
*/
|
|
55
|
-
import { apiConnector as api, defined } from "
|
|
56
|
-
import { guardedFetch, retryAfterMs, } from "
|
|
57
|
-
import { ConnectorCallError } from "
|
|
56
|
+
import { apiConnector as api, defined } from "../../connectors/api-connector.js";
|
|
57
|
+
import { guardedFetch, retryAfterMs, } from "../../connectors/guarded-fetch.js";
|
|
58
|
+
import { ConnectorCallError } from "../../errors.js";
|
|
59
|
+
import { keys, optionsOf } from "../../config-schema.js";
|
|
60
|
+
import { PROVIDER_COMMON } from "../../connectors/option-shapes.js";
|
|
61
|
+
import { asProviderFactory } from "../../provider.js";
|
|
58
62
|
/** Every church's API lives at `https://<subdomain>.breezechms.com/api`. */
|
|
59
63
|
export const BREEZE_HOST_SUFFIX = ".breezechms.com";
|
|
60
64
|
const DEFAULT_PAGE_SIZE = 100;
|
|
@@ -71,9 +75,7 @@ const BREEZE_MAX_RESPONSE_BYTES = 8 * 1024 * 1024;
|
|
|
71
75
|
/** One DNS label: what `<subdomain>.breezechms.com` can actually be. */
|
|
72
76
|
const SUBDOMAIN_PATTERN = /^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/;
|
|
73
77
|
function asRecord(value) {
|
|
74
|
-
return value && typeof value === "object" && !Array.isArray(value)
|
|
75
|
-
? value
|
|
76
|
-
: {};
|
|
78
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
77
79
|
}
|
|
78
80
|
function asArray(value) {
|
|
79
81
|
return Array.isArray(value) ? value : [];
|
|
@@ -96,9 +98,7 @@ function flag(value) {
|
|
|
96
98
|
return value === true || value === 1 || value === "1";
|
|
97
99
|
}
|
|
98
100
|
function idString(value) {
|
|
99
|
-
return value === undefined || value === null || value === ""
|
|
100
|
-
? undefined
|
|
101
|
-
: String(value);
|
|
101
|
+
return value === undefined || value === null || value === "" ? undefined : String(value);
|
|
102
102
|
}
|
|
103
103
|
// --- Transport and failures ---------------------------------------------------
|
|
104
104
|
/**
|
|
@@ -158,7 +158,9 @@ function breezeFailure(status, headers, text) {
|
|
|
158
158
|
const wait = retryAfterMs(headers);
|
|
159
159
|
return new ConnectorCallError("unavailable", `Breeze is failing upstream (HTTP ${status}).`, wait === undefined ? {} : { retryAfterMs: wait });
|
|
160
160
|
}
|
|
161
|
-
return new ConnectorCallError("connector_call_failed", `Breeze request failed (HTTP ${status}).${detail}`, {
|
|
161
|
+
return new ConnectorCallError("connector_call_failed", `Breeze request failed (HTTP ${status}).${detail}`, {
|
|
162
|
+
retryable: false,
|
|
163
|
+
});
|
|
162
164
|
}
|
|
163
165
|
function shortText(value) {
|
|
164
166
|
if (typeof value === "string")
|
|
@@ -211,7 +213,9 @@ async function callBreeze(send, request, ctx, options = {}) {
|
|
|
211
213
|
// only the parse does. A hatch hands back what arrived.
|
|
212
214
|
if (options.raw)
|
|
213
215
|
return text;
|
|
214
|
-
throw new ConnectorCallError("connector_call_failed", "Breeze returned a non-JSON successful response.", {
|
|
216
|
+
throw new ConnectorCallError("connector_call_failed", "Breeze returned a non-JSON successful response.", {
|
|
217
|
+
retryable: false,
|
|
218
|
+
});
|
|
215
219
|
}
|
|
216
220
|
const failure = reportedFailure(payload);
|
|
217
221
|
if (failure)
|
|
@@ -253,7 +257,23 @@ const READ_ENDPOINTS = new Map([
|
|
|
253
257
|
["/account/summary", []],
|
|
254
258
|
["/account/list_log", ["action", "start", "end", "user_id", "details", "limit"]],
|
|
255
259
|
// Undocumented since ~2023-09; parameters from the 2023-06-07 reference.
|
|
256
|
-
[
|
|
260
|
+
[
|
|
261
|
+
"/giving/list",
|
|
262
|
+
[
|
|
263
|
+
"start",
|
|
264
|
+
"end",
|
|
265
|
+
"person_id",
|
|
266
|
+
"include_family",
|
|
267
|
+
"amount_min",
|
|
268
|
+
"amount_max",
|
|
269
|
+
"method_ids",
|
|
270
|
+
"fund_ids",
|
|
271
|
+
"envelope_number",
|
|
272
|
+
"batches",
|
|
273
|
+
"forms",
|
|
274
|
+
"pledge_ids",
|
|
275
|
+
],
|
|
276
|
+
],
|
|
257
277
|
["/giving/view", ["payment_id"]],
|
|
258
278
|
["/funds/list", ["include_totals"]],
|
|
259
279
|
["/pledges/list_campaigns", []],
|
|
@@ -289,8 +309,7 @@ function queryPairs(value) {
|
|
|
289
309
|
throw new ConnectorCallError("invalid_args", `Query parameter ${name} appears more than once; Breeze reads one value per name.`);
|
|
290
310
|
}
|
|
291
311
|
const item = pair["value"];
|
|
292
|
-
query[name] =
|
|
293
|
-
item !== null && typeof item === "object" ? JSON.stringify(item) : item;
|
|
312
|
+
query[name] = item !== null && typeof item === "object" ? JSON.stringify(item) : item;
|
|
294
313
|
}
|
|
295
314
|
return query;
|
|
296
315
|
}
|
|
@@ -325,9 +344,7 @@ function projectPerson(value) {
|
|
|
325
344
|
nickName: person["nick_name"] || undefined,
|
|
326
345
|
middleName: person["middle_name"] || undefined,
|
|
327
346
|
maidenName: person["maiden_name"] || undefined,
|
|
328
|
-
details: details && typeof details === "object" && !Array.isArray(details)
|
|
329
|
-
? details
|
|
330
|
-
: undefined,
|
|
347
|
+
details: details && typeof details === "object" && !Array.isArray(details) ? details : undefined,
|
|
331
348
|
family: family.length ? family.map(projectFamilyMember) : undefined,
|
|
332
349
|
});
|
|
333
350
|
}
|
|
@@ -610,8 +627,12 @@ function tools(send, defaultPageSize) {
|
|
|
610
627
|
outputSchema: {
|
|
611
628
|
type: "object",
|
|
612
629
|
properties: {
|
|
613
|
-
id: { type: "string" },
|
|
614
|
-
|
|
630
|
+
id: { type: "string" },
|
|
631
|
+
name: { type: "string" },
|
|
632
|
+
subdomain: { type: "string" },
|
|
633
|
+
timezone: { type: "string" },
|
|
634
|
+
country: { type: "string" },
|
|
635
|
+
currency: { type: "string" },
|
|
615
636
|
},
|
|
616
637
|
required: ["name"],
|
|
617
638
|
},
|
|
@@ -637,11 +658,16 @@ function tools(send, defaultPageSize) {
|
|
|
637
658
|
tagId: idProperty("Only people carrying this tag id from list_tags."),
|
|
638
659
|
filter: {
|
|
639
660
|
type: "object",
|
|
640
|
-
description:
|
|
661
|
+
description: 'Breeze filter_json: profile fieldId to option ids joined by \'-\', e.g. {"2000138015":"226-227"}.',
|
|
662
|
+
},
|
|
663
|
+
includeDetails: {
|
|
664
|
+
type: "boolean",
|
|
665
|
+
description: "Include every profile field (slower, larger). Defaults to false.",
|
|
641
666
|
},
|
|
642
|
-
includeDetails: { type: "boolean", description: "Include every profile field (slower, larger). Defaults to false." },
|
|
643
667
|
limit: {
|
|
644
|
-
type: "integer",
|
|
668
|
+
type: "integer",
|
|
669
|
+
minimum: 1,
|
|
670
|
+
maximum: MAX_PAGE_SIZE,
|
|
645
671
|
description: `People per page, 1 to connecta's ${MAX_PAGE_SIZE}. Defaults to ${defaultPageSize}.`,
|
|
646
672
|
},
|
|
647
673
|
cursor: { type: "string", pattern: ID_PATTERN, description: "Opaque nextCursor from the previous page." },
|
|
@@ -712,8 +738,11 @@ function tools(send, defaultPageSize) {
|
|
|
712
738
|
items: {
|
|
713
739
|
type: "object",
|
|
714
740
|
properties: {
|
|
715
|
-
fieldId: { type: "string" },
|
|
716
|
-
|
|
741
|
+
fieldId: { type: "string" },
|
|
742
|
+
name: { type: "string" },
|
|
743
|
+
type: { type: "string" },
|
|
744
|
+
section: { type: "string" },
|
|
745
|
+
options: { type: "array", items: { type: "object" } },
|
|
717
746
|
},
|
|
718
747
|
required: ["fieldId", "name", "type"],
|
|
719
748
|
},
|
|
@@ -763,7 +792,9 @@ function tools(send, defaultPageSize) {
|
|
|
763
792
|
end: dateProperty("Last day, YYYY-MM-DD. Defaults to the end of this month."),
|
|
764
793
|
calendarId: idProperty("Only events on this calendar from list_calendars."),
|
|
765
794
|
limit: {
|
|
766
|
-
type: "integer",
|
|
795
|
+
type: "integer",
|
|
796
|
+
minimum: 1,
|
|
797
|
+
maximum: MAX_EVENT_LIMIT,
|
|
767
798
|
description: `Instances returned, 1 to Breeze's ${MAX_EVENT_LIMIT}. Defaults to ${DEFAULT_EVENT_LIMIT}.`,
|
|
768
799
|
},
|
|
769
800
|
raw: RAW_PROPERTY,
|
|
@@ -776,9 +807,12 @@ function tools(send, defaultPageSize) {
|
|
|
776
807
|
items: {
|
|
777
808
|
type: "object",
|
|
778
809
|
properties: {
|
|
779
|
-
id: { type: "string", description: "Instance id." },
|
|
780
|
-
|
|
781
|
-
|
|
810
|
+
id: { type: "string", description: "Instance id." },
|
|
811
|
+
eventId: { type: "string", description: "Series id." },
|
|
812
|
+
name: { type: "string" },
|
|
813
|
+
calendarId: { type: "string" },
|
|
814
|
+
startsAt: { type: ["string", "null"] },
|
|
815
|
+
endsAt: { type: ["string", "null"] },
|
|
782
816
|
},
|
|
783
817
|
required: ["id", "name"],
|
|
784
818
|
},
|
|
@@ -790,7 +824,10 @@ function tools(send, defaultPageSize) {
|
|
|
790
824
|
handler: async (args, ctx) => {
|
|
791
825
|
const limit = args["limit"] ?? DEFAULT_EVENT_LIMIT;
|
|
792
826
|
const rows = asArray(await get("/events", {
|
|
793
|
-
start: args["start"],
|
|
827
|
+
start: args["start"],
|
|
828
|
+
end: args["end"],
|
|
829
|
+
category_id: args["calendarId"],
|
|
830
|
+
limit,
|
|
794
831
|
}, ctx));
|
|
795
832
|
return {
|
|
796
833
|
events: args["raw"] === true ? rows : rows.map(projectEvent),
|
|
@@ -841,8 +878,11 @@ function tools(send, defaultPageSize) {
|
|
|
841
878
|
items: {
|
|
842
879
|
type: "object",
|
|
843
880
|
properties: {
|
|
844
|
-
personId: { type: "string" },
|
|
845
|
-
|
|
881
|
+
personId: { type: "string" },
|
|
882
|
+
firstName: { type: "string" },
|
|
883
|
+
lastName: { type: "string" },
|
|
884
|
+
checkedInAt: { type: ["string", "null"] },
|
|
885
|
+
checkedOutAt: { type: ["string", "null"] },
|
|
846
886
|
},
|
|
847
887
|
required: ["personId"],
|
|
848
888
|
},
|
|
@@ -853,7 +893,9 @@ function tools(send, defaultPageSize) {
|
|
|
853
893
|
handler: async (args, ctx) => {
|
|
854
894
|
const wantDetails = args["includeNames"] === true || args["raw"] === true;
|
|
855
895
|
const rows = asArray(await get("/events/attendance/list", {
|
|
856
|
-
instance_id: args["instanceId"],
|
|
896
|
+
instance_id: args["instanceId"],
|
|
897
|
+
type: "person",
|
|
898
|
+
details: wantDetails ? "true" : "false",
|
|
857
899
|
}, ctx));
|
|
858
900
|
if (args["raw"] === true)
|
|
859
901
|
return { attendance: rows };
|
|
@@ -887,8 +929,11 @@ function tools(send, defaultPageSize) {
|
|
|
887
929
|
items: {
|
|
888
930
|
type: "object",
|
|
889
931
|
properties: {
|
|
890
|
-
id: { type: "string" },
|
|
891
|
-
|
|
932
|
+
id: { type: "string" },
|
|
933
|
+
name: { type: "string" },
|
|
934
|
+
slug: { type: "string" },
|
|
935
|
+
archived: { type: "boolean" },
|
|
936
|
+
createdAt: { type: "string" },
|
|
892
937
|
},
|
|
893
938
|
required: ["id", "name"],
|
|
894
939
|
},
|
|
@@ -900,8 +945,11 @@ function tools(send, defaultPageSize) {
|
|
|
900
945
|
forms: asArray(await get("/forms/list_forms", { is_archived: args["archived"] === true ? 1 : 0 }, ctx)).map((value) => {
|
|
901
946
|
const form = asRecord(value);
|
|
902
947
|
return compact({
|
|
903
|
-
id: idString(form["id"]),
|
|
904
|
-
|
|
948
|
+
id: idString(form["id"]),
|
|
949
|
+
name: form["name"],
|
|
950
|
+
slug: form["url_slug"],
|
|
951
|
+
archived: flag(form["is_archived"]),
|
|
952
|
+
createdAt: form["created_on"],
|
|
905
953
|
});
|
|
906
954
|
}),
|
|
907
955
|
}),
|
|
@@ -919,7 +967,9 @@ function tools(send, defaultPageSize) {
|
|
|
919
967
|
items: {
|
|
920
968
|
type: "object",
|
|
921
969
|
properties: {
|
|
922
|
-
fieldId: { type: "string" },
|
|
970
|
+
fieldId: { type: "string" },
|
|
971
|
+
name: { type: "string" },
|
|
972
|
+
type: { type: "string" },
|
|
923
973
|
options: { type: "array", items: { type: "object" } },
|
|
924
974
|
},
|
|
925
975
|
required: ["fieldId", "name"],
|
|
@@ -951,8 +1001,10 @@ function tools(send, defaultPageSize) {
|
|
|
951
1001
|
items: {
|
|
952
1002
|
type: "object",
|
|
953
1003
|
properties: {
|
|
954
|
-
id: { type: "string" },
|
|
955
|
-
|
|
1004
|
+
id: { type: "string" },
|
|
1005
|
+
personId: { type: ["string", "null"] },
|
|
1006
|
+
createdAt: { type: "string" },
|
|
1007
|
+
responses: { type: "object" },
|
|
956
1008
|
},
|
|
957
1009
|
required: ["id"],
|
|
958
1010
|
},
|
|
@@ -962,7 +1014,8 @@ function tools(send, defaultPageSize) {
|
|
|
962
1014
|
},
|
|
963
1015
|
handler: async (args, ctx) => ({
|
|
964
1016
|
entries: asArray(await get("/forms/list_form_entries", {
|
|
965
|
-
form_id: args["formId"],
|
|
1017
|
+
form_id: args["formId"],
|
|
1018
|
+
details: args["includeResponses"] === true ? 1 : 0,
|
|
966
1019
|
}, ctx)).map((value) => {
|
|
967
1020
|
const entry = asRecord(value);
|
|
968
1021
|
return compact({
|
|
@@ -987,8 +1040,11 @@ function tools(send, defaultPageSize) {
|
|
|
987
1040
|
items: {
|
|
988
1041
|
type: "object",
|
|
989
1042
|
properties: {
|
|
990
|
-
personId: { type: "string" },
|
|
991
|
-
|
|
1043
|
+
personId: { type: "string" },
|
|
1044
|
+
roleIds: { type: "array", items: { type: "string" } },
|
|
1045
|
+
response: { type: "string" },
|
|
1046
|
+
comment: { type: "string" },
|
|
1047
|
+
rsvpedAt: { type: ["string", "null"] },
|
|
992
1048
|
},
|
|
993
1049
|
required: ["personId", "roleIds"],
|
|
994
1050
|
},
|
|
@@ -1033,7 +1089,8 @@ function tools(send, defaultPageSize) {
|
|
|
1033
1089
|
const role = asRecord(value);
|
|
1034
1090
|
const quantity = Number(role["quantity"]);
|
|
1035
1091
|
return compact({
|
|
1036
|
-
id: idString(role["id"]),
|
|
1092
|
+
id: idString(role["id"]),
|
|
1093
|
+
name: role["name"],
|
|
1037
1094
|
quantity: Number.isFinite(quantity) ? quantity : undefined,
|
|
1038
1095
|
});
|
|
1039
1096
|
}),
|
|
@@ -1045,7 +1102,9 @@ function tools(send, defaultPageSize) {
|
|
|
1045
1102
|
annotations: readOnly,
|
|
1046
1103
|
inputSchema: namedInput({
|
|
1047
1104
|
action: {
|
|
1048
|
-
type: "string",
|
|
1105
|
+
type: "string",
|
|
1106
|
+
pattern: "^[a-z_]+$",
|
|
1107
|
+
maxLength: 40,
|
|
1049
1108
|
description: "Logged action, e.g. person_updated, tag_assign, contribution_added; the guide lists all.",
|
|
1050
1109
|
},
|
|
1051
1110
|
start: dateProperty("Only actions on or after this day, YYYY-MM-DD."),
|
|
@@ -1053,7 +1112,9 @@ function tools(send, defaultPageSize) {
|
|
|
1053
1112
|
userId: idProperty("Only actions by this Breeze user id."),
|
|
1054
1113
|
includeDetails: { type: "boolean", description: "Include Breeze's unstandardized description." },
|
|
1055
1114
|
limit: {
|
|
1056
|
-
type: "integer",
|
|
1115
|
+
type: "integer",
|
|
1116
|
+
minimum: 1,
|
|
1117
|
+
maximum: MAX_LOG_LIMIT,
|
|
1057
1118
|
description: `Rows returned, 1 to Breeze's ${MAX_LOG_LIMIT}. Defaults to ${DEFAULT_LOG_LIMIT}.`,
|
|
1058
1119
|
},
|
|
1059
1120
|
}, ["action"]),
|
|
@@ -1065,9 +1126,12 @@ function tools(send, defaultPageSize) {
|
|
|
1065
1126
|
items: {
|
|
1066
1127
|
type: "object",
|
|
1067
1128
|
properties: {
|
|
1068
|
-
id: { type: "string" },
|
|
1129
|
+
id: { type: "string" },
|
|
1130
|
+
action: { type: "string" },
|
|
1131
|
+
userId: { type: "string" },
|
|
1069
1132
|
object: { description: "Parsed object_json, usually the affected id." },
|
|
1070
|
-
createdAt: { type: "string" },
|
|
1133
|
+
createdAt: { type: "string" },
|
|
1134
|
+
details: {},
|
|
1071
1135
|
},
|
|
1072
1136
|
required: ["id", "action"],
|
|
1073
1137
|
},
|
|
@@ -1079,8 +1143,12 @@ function tools(send, defaultPageSize) {
|
|
|
1079
1143
|
handler: async (args, ctx) => {
|
|
1080
1144
|
const limit = args["limit"] ?? DEFAULT_LOG_LIMIT;
|
|
1081
1145
|
const rows = asArray(await get("/account/list_log", {
|
|
1082
|
-
action: args["action"],
|
|
1083
|
-
|
|
1146
|
+
action: args["action"],
|
|
1147
|
+
start: args["start"],
|
|
1148
|
+
end: args["end"],
|
|
1149
|
+
user_id: args["userId"],
|
|
1150
|
+
details: args["includeDetails"] === true ? 1 : 0,
|
|
1151
|
+
limit,
|
|
1084
1152
|
}, ctx));
|
|
1085
1153
|
return {
|
|
1086
1154
|
entries: rows.map((value) => {
|
|
@@ -1123,9 +1191,15 @@ function tools(send, defaultPageSize) {
|
|
|
1123
1191
|
items: {
|
|
1124
1192
|
type: "object",
|
|
1125
1193
|
properties: {
|
|
1126
|
-
id: { type: "string" },
|
|
1127
|
-
|
|
1128
|
-
|
|
1194
|
+
id: { type: "string" },
|
|
1195
|
+
paidOn: { type: "string" },
|
|
1196
|
+
amount: { type: "string" },
|
|
1197
|
+
method: { type: "string" },
|
|
1198
|
+
personId: { type: "string" },
|
|
1199
|
+
firstName: { type: "string" },
|
|
1200
|
+
lastName: { type: "string" },
|
|
1201
|
+
batchNumber: { type: "string" },
|
|
1202
|
+
funds: { type: "array", items: { type: "object" } },
|
|
1129
1203
|
},
|
|
1130
1204
|
required: ["id", "amount"],
|
|
1131
1205
|
},
|
|
@@ -1139,16 +1213,21 @@ function tools(send, defaultPageSize) {
|
|
|
1139
1213
|
if (args["includeFamily"] === true && args["personId"] === undefined) {
|
|
1140
1214
|
throw new ConnectorCallError("invalid_args", "includeFamily needs a personId.");
|
|
1141
1215
|
}
|
|
1142
|
-
const joined = (value) => Array.isArray(value) ? value.join("-") : undefined;
|
|
1216
|
+
const joined = (value) => (Array.isArray(value) ? value.join("-") : undefined);
|
|
1143
1217
|
// Breeze's 2023 table says DD-MM-YYYY while its own example request
|
|
1144
1218
|
// sends 2022-1-15; the server parses both, so the unambiguous ISO day
|
|
1145
1219
|
// is what the schema accepts and what goes on the wire.
|
|
1146
1220
|
const rows = asArray(await get("/giving/list", {
|
|
1147
|
-
start: args["start"],
|
|
1221
|
+
start: args["start"],
|
|
1222
|
+
end: args["end"],
|
|
1223
|
+
person_id: args["personId"],
|
|
1148
1224
|
include_family: args["includeFamily"] === true ? 1 : undefined,
|
|
1149
|
-
amount_min: args["amountMin"],
|
|
1150
|
-
|
|
1151
|
-
|
|
1225
|
+
amount_min: args["amountMin"],
|
|
1226
|
+
amount_max: args["amountMax"],
|
|
1227
|
+
fund_ids: joined(args["fundIds"]),
|
|
1228
|
+
method_ids: joined(args["methodIds"]),
|
|
1229
|
+
batches: joined(args["batchNumbers"]),
|
|
1230
|
+
envelope_number: args["envelopeNumber"],
|
|
1152
1231
|
}, ctx));
|
|
1153
1232
|
return {
|
|
1154
1233
|
contributions: args["raw"] === true ? rows : rows.map(projectContribution),
|
|
@@ -1170,8 +1249,10 @@ function tools(send, defaultPageSize) {
|
|
|
1170
1249
|
items: {
|
|
1171
1250
|
type: "object",
|
|
1172
1251
|
properties: {
|
|
1173
|
-
id: { type: "string" },
|
|
1174
|
-
|
|
1252
|
+
id: { type: "string" },
|
|
1253
|
+
name: { type: "string" },
|
|
1254
|
+
taxDeductible: { type: "boolean" },
|
|
1255
|
+
isDefault: { type: "boolean" },
|
|
1175
1256
|
},
|
|
1176
1257
|
required: ["id", "name"],
|
|
1177
1258
|
},
|
|
@@ -1183,8 +1264,10 @@ function tools(send, defaultPageSize) {
|
|
|
1183
1264
|
funds: asArray(await get("/funds/list", {}, ctx)).map((value) => {
|
|
1184
1265
|
const fund = asRecord(value);
|
|
1185
1266
|
return compact({
|
|
1186
|
-
id: idString(fund["id"]),
|
|
1187
|
-
|
|
1267
|
+
id: idString(fund["id"]),
|
|
1268
|
+
name: fund["name"],
|
|
1269
|
+
taxDeductible: flag(fund["tax_deductible"]),
|
|
1270
|
+
isDefault: flag(fund["is_default"]),
|
|
1188
1271
|
});
|
|
1189
1272
|
}),
|
|
1190
1273
|
}),
|
|
@@ -1201,7 +1284,8 @@ function tools(send, defaultPageSize) {
|
|
|
1201
1284
|
outputSchema: PERSON_SCHEMA,
|
|
1202
1285
|
handler: async (args, ctx) => {
|
|
1203
1286
|
const payload = await get("/people/add", {
|
|
1204
|
-
first: args["firstName"],
|
|
1287
|
+
first: args["firstName"],
|
|
1288
|
+
last: args["lastName"],
|
|
1205
1289
|
fields_json: args["fields"] === undefined ? undefined : fieldsJson(args["fields"]),
|
|
1206
1290
|
}, ctx);
|
|
1207
1291
|
const person = Array.isArray(payload) ? payload[0] : payload;
|
|
@@ -1229,7 +1313,10 @@ function tools(send, defaultPageSize) {
|
|
|
1229
1313
|
name: "assign_tag",
|
|
1230
1314
|
description: "Add one tag to one person. Tag ids come from list_tags; adding a tag the person already has changes nothing.",
|
|
1231
1315
|
annotations: additive,
|
|
1232
|
-
inputSchema: namedInput({ personId: PERSON_ID, tagId: idProperty("Tag id from list_tags.") }, [
|
|
1316
|
+
inputSchema: namedInput({ personId: PERSON_ID, tagId: idProperty("Tag id from list_tags.") }, [
|
|
1317
|
+
"personId",
|
|
1318
|
+
"tagId",
|
|
1319
|
+
]),
|
|
1233
1320
|
outputSchema: WROTE_SCHEMA("assigned"),
|
|
1234
1321
|
handler: async (args, ctx) => {
|
|
1235
1322
|
requireTrue(await get("/tags/assign", { person_id: args["personId"], tag_id: args["tagId"] }, ctx), "the tag assignment");
|
|
@@ -1240,7 +1327,10 @@ function tools(send, defaultPageSize) {
|
|
|
1240
1327
|
name: "unassign_tag",
|
|
1241
1328
|
description: "Remove one tag from one person. The tag itself and its other people are untouched.",
|
|
1242
1329
|
annotations: destructive,
|
|
1243
|
-
inputSchema: namedInput({ personId: PERSON_ID, tagId: idProperty("Tag id from list_tags.") }, [
|
|
1330
|
+
inputSchema: namedInput({ personId: PERSON_ID, tagId: idProperty("Tag id from list_tags.") }, [
|
|
1331
|
+
"personId",
|
|
1332
|
+
"tagId",
|
|
1333
|
+
]),
|
|
1244
1334
|
outputSchema: WROTE_SCHEMA("unassigned"),
|
|
1245
1335
|
handler: async (args, ctx) => {
|
|
1246
1336
|
requireTrue(await get("/tags/unassign", { person_id: args["personId"], tag_id: args["tagId"] }, ctx), "the tag removal");
|
|
@@ -1255,7 +1345,9 @@ function tools(send, defaultPageSize) {
|
|
|
1255
1345
|
outputSchema: WROTE_SCHEMA("checkedIn"),
|
|
1256
1346
|
handler: async (args, ctx) => {
|
|
1257
1347
|
requireTrue(await get("/events/attendance/add", {
|
|
1258
|
-
person_id: args["personId"],
|
|
1348
|
+
person_id: args["personId"],
|
|
1349
|
+
instance_id: args["instanceId"],
|
|
1350
|
+
direction: "in",
|
|
1259
1351
|
}, ctx), "the check-in");
|
|
1260
1352
|
return { checkedIn: true };
|
|
1261
1353
|
},
|
|
@@ -1267,75 +1359,7 @@ function usageGuide(subdomain, purpose, instructions) {
|
|
|
1267
1359
|
const churchInstructions = instructions?.trim();
|
|
1268
1360
|
return `# Breeze ChMS usage
|
|
1269
1361
|
|
|
1270
|
-
Church database for ${subdomain}.
|
|
1271
|
-
|
|
1272
|
-
Church purpose: ${purpose}
|
|
1273
|
-
|
|
1274
|
-
## Sensitive data: reduce in code
|
|
1275
|
-
|
|
1276
|
-
People records carry home addresses, phones, birthdates, and family ties, and
|
|
1277
|
-
giving records reveal who gives and how much — religious affiliation by proxy.
|
|
1278
|
-
Read them inside \`execute_code\` and return only the counts, totals, or the
|
|
1279
|
-
few fields the task needs. Never echo whole profiles or donor lists.
|
|
1280
|
-
|
|
1281
|
-
## Ids and profile fields
|
|
1282
|
-
|
|
1283
|
-
- Ids are numeric strings. Read them from a list tool; never guess one.
|
|
1284
|
-
- Events have two ids: an instance id (\`list_events\` \`id\`) for one
|
|
1285
|
-
occurrence, and a series \`eventId\`. Attendance, volunteers, and
|
|
1286
|
-
check-in take the instance id.
|
|
1287
|
-
- Person \`details\` are keyed by profile \`fieldId\`, not by name. Call
|
|
1288
|
-
\`list_profile_fields\` once and map ids to names in code. Multiple-choice
|
|
1289
|
-
values and \`list_people\` filters use option ids from the same call;
|
|
1290
|
-
join several with \`-\`.
|
|
1291
|
-
- \`list_people\` has no name search. List without details and match names
|
|
1292
|
-
in code, then \`get_person\` the hits.
|
|
1293
|
-
- Projections rename Breeze's snake_case fields to camelCase and drop photo
|
|
1294
|
-
paths and internal columns; \`raw: true\` returns Breeze's rows.
|
|
1295
|
-
|
|
1296
|
-
## Pagination
|
|
1297
|
-
|
|
1298
|
-
\`list_people\` pages by \`cursor\`: continue while \`page.hasMore\`. Breeze
|
|
1299
|
-
reports no total, so a full page sets \`hasMore\` and the next may be empty.
|
|
1300
|
-
\`list_events\` and \`list_account_log\` do not page: \`truncated: true\`
|
|
1301
|
-
means narrow the date range. Other lists return everything.
|
|
1302
|
-
|
|
1303
|
-
## Giving
|
|
1304
|
-
|
|
1305
|
-
\`list_contributions\` and \`list_funds\` call endpoints Breeze removed from
|
|
1306
|
-
its public reference in 2023 but still serves. They may change or vanish
|
|
1307
|
-
without notice; a failure there is not your argument's fault. Amounts are
|
|
1308
|
-
decimal strings; \`totalAmount\` is an exact sum. Online gifts processed by
|
|
1309
|
-
Tithe.ly arrive through its sync, batched per deposit, so the latest days
|
|
1310
|
-
may be missing. Read the currency from \`get_account_summary\`.
|
|
1311
|
-
|
|
1312
|
-
## Writes and the hatches
|
|
1313
|
-
|
|
1314
|
-
- Every write, \`add_person\`, \`assign_tag\`, and \`record_check_in\`
|
|
1315
|
-
included, is a \`call_destructive_tool\` call unless the deployment exempts
|
|
1316
|
-
it in \`execute.approval\`; a program inside \`execute_code\` is refused
|
|
1317
|
-
the rest. Those three only add, and \`add_person\` never deduplicates.
|
|
1318
|
-
- \`update_person\` field values: text, date (M/D/YYYY), or option id in
|
|
1319
|
-
\`response\`; email, phone, address, and family_role values in \`details\`.
|
|
1320
|
-
- Every Breeze call is a GET, writes included, so the hatches split by
|
|
1321
|
-
endpoint. \`breeze_api_get\` admits only reviewed read endpoints and their
|
|
1322
|
-
documented parameters, such as \`/tags/list_folders\`,
|
|
1323
|
-
\`/events/list_event\`, \`/events/attendance/eligible\`, \`/giving/view\`,
|
|
1324
|
-
and \`/pledges/list_campaigns\`; it refuses anything else. Everything else
|
|
1325
|
-
— event, family, volunteer, and form writes, giving writes, check-out,
|
|
1326
|
-
undocumented parameters — is \`breeze_api_mutate\`. Paths are below
|
|
1327
|
-
\`/api\`; \`*_json\` values may be passed as objects.
|
|
1328
|
-
- \`list_account_log\` actions include person_created, person_updated,
|
|
1329
|
-
person_deleted, tag_assign, tag_unassign, event_created,
|
|
1330
|
-
attendance_deleted, form_entry_updated, contribution_added,
|
|
1331
|
-
contribution_updated, contribution_deleted, and batch_updated.
|
|
1332
|
-
|
|
1333
|
-
## Rate limits
|
|
1334
|
-
|
|
1335
|
-
Breeze publishes no limit and sends no rate headers; a third party reports
|
|
1336
|
-
about 20 requests per minute. Keep loops sequential and prefer one list call
|
|
1337
|
-
over many single reads.
|
|
1338
|
-
${churchInstructions ? `\n## Church instructions\n\n${churchInstructions}\n` : ""}`;
|
|
1362
|
+
Church database for ${subdomain}${skill.fragments.guide_0}${purpose}${skill.fragments.guide_1}${churchInstructions ? `\n## ${skill.instructionsHeading}\n\n${churchInstructions}\n` : ""}`;
|
|
1339
1363
|
}
|
|
1340
1364
|
// --- Construction --------------------------------------------------------------
|
|
1341
1365
|
function normalizeSubdomain(raw) {
|
|
@@ -1345,17 +1369,31 @@ function normalizeSubdomain(raw) {
|
|
|
1345
1369
|
}
|
|
1346
1370
|
return value;
|
|
1347
1371
|
}
|
|
1372
|
+
/** The closed options breeze() accepts; see `assertKnownOptions`. */
|
|
1373
|
+
const BREEZE_OPTIONS = optionsOf()({ ...PROVIDER_COMMON, ...keys("subdomain", "defaultPageSize") });
|
|
1348
1374
|
/** A maintained Breeze ChMS connection for one church's subdomain. */
|
|
1349
|
-
export
|
|
1375
|
+
export const breeze = asProviderFactory({
|
|
1376
|
+
name: "breeze",
|
|
1377
|
+
title: "Breeze ChMS",
|
|
1378
|
+
kind: "api",
|
|
1379
|
+
readme: "Breeze ChMS",
|
|
1380
|
+
bundle: {
|
|
1381
|
+
"baselineGzip": 20637,
|
|
1382
|
+
"maxGzip": 80637,
|
|
1383
|
+
"note": "./providers/breeze starts at 20,637 B gzip: a hand-written api() surface with no hosted-MCP interface, so it carries no MCP SDK. The cap uses the existing baseline + 60,000 B policy.",
|
|
1384
|
+
},
|
|
1385
|
+
skill,
|
|
1386
|
+
options: BREEZE_OPTIONS,
|
|
1387
|
+
create: breezeConnector,
|
|
1388
|
+
});
|
|
1389
|
+
function breezeConnector(id, options) {
|
|
1350
1390
|
const purpose = typeof options.purpose === "string" ? options.purpose.trim() : "";
|
|
1351
1391
|
if (!purpose) {
|
|
1352
1392
|
throw new Error("breeze() requires a non-empty church purpose.");
|
|
1353
1393
|
}
|
|
1354
1394
|
const subdomain = normalizeSubdomain(options.subdomain);
|
|
1355
1395
|
const defaultPageSize = options.defaultPageSize ?? DEFAULT_PAGE_SIZE;
|
|
1356
|
-
if (!Number.isInteger(defaultPageSize) ||
|
|
1357
|
-
defaultPageSize < 1 ||
|
|
1358
|
-
defaultPageSize > MAX_PAGE_SIZE) {
|
|
1396
|
+
if (!Number.isInteger(defaultPageSize) || defaultPageSize < 1 || defaultPageSize > MAX_PAGE_SIZE) {
|
|
1359
1397
|
throw new Error(`breeze() defaultPageSize must be a whole number between 1 and ${MAX_PAGE_SIZE}.`);
|
|
1360
1398
|
}
|
|
1361
1399
|
const send = breezeTransport(subdomain);
|
|
@@ -1377,9 +1415,15 @@ export function breeze(id, options) {
|
|
|
1377
1415
|
const account = asRecord(await callBreeze(send, { method: "GET", path: "/account/summary" }, { ...ctx, credential: { get: async () => value, getAll: async () => ({ value }) } }));
|
|
1378
1416
|
const reported = typeof account["subdomain"] === "string" ? account["subdomain"].toLowerCase() : undefined;
|
|
1379
1417
|
if (reported && reported !== subdomain) {
|
|
1380
|
-
return {
|
|
1418
|
+
return {
|
|
1419
|
+
ok: false,
|
|
1420
|
+
message: `The key belongs to ${reported}${BREEZE_HOST_SUFFIX}, not ${subdomain}${BREEZE_HOST_SUFFIX}.`,
|
|
1421
|
+
};
|
|
1381
1422
|
}
|
|
1382
|
-
return {
|
|
1423
|
+
return {
|
|
1424
|
+
ok: true,
|
|
1425
|
+
message: `Authenticated to ${String(account["name"] ?? "the church account")} (${subdomain}${BREEZE_HOST_SUFFIX}).`,
|
|
1426
|
+
};
|
|
1383
1427
|
}
|
|
1384
1428
|
catch (error) {
|
|
1385
1429
|
return {
|