@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.
- package/CHANGELOG.md +788 -5
- package/README.md +62 -42
- package/bin/connecta.mjs +110 -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/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 +283 -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 +368 -224
- 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 +631 -0
- package/dist/config.js +503 -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 +84 -35
- 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 +119 -0
- package/dist/downstream-input.js +323 -0
- package/dist/errors.d.ts +97 -20
- package/dist/errors.js +158 -80
- package/dist/execute.js +453 -305
- 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 +24 -9
- package/dist/executors/quickjs-child.js +3 -4
- package/dist/executors/quickjs-runtime.js +147 -59
- package/dist/executors/quickjs.js +29 -35
- package/dist/favicon.js +1 -2
- package/dist/fix-prompt.js +1 -3
- package/dist/guest-runtime.js +188 -0
- package/dist/guest-types.d.ts +176 -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 +230 -73
- 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 +76 -0
- package/dist/meta-tool-names.d.ts +2 -0
- package/dist/meta-tool-names.js +3 -0
- package/dist/meta-tools.js +285 -209
- 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 +117 -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-source.js +14 -2
- package/dist/{exempt-writes.js → program-writes.js} +55 -18
- 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/{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/{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 +108 -171
- package/dist/registry.js +513 -925
- package/dist/request-state.js +21 -0
- package/dist/resource-read.js +100 -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 +356 -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 +52 -0
- package/dist/sent-secrets.js +474 -0
- package/dist/server.js +28 -71
- package/dist/skills.js +406 -174
- package/dist/sqlite.d.ts +48 -0
- package/dist/sqlite.js +166 -0
- package/dist/storage/keys.js +428 -0
- package/dist/storage/memory.js +7 -0
- package/dist/storage/sql.d.ts +66 -0
- package/dist/storage/sql.js +534 -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 +320 -54
- 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 +137 -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 +434 -0
- package/documentation/architecture.md +664 -231
- package/documentation/auth.md +936 -546
- package/documentation/code-mode.md +501 -312
- package/documentation/meta-tools.md +449 -200
- package/documentation/operator-tests.md +93 -0
- package/documentation/provider-migration-0.29.md +60 -0
- package/examples/worker/AGENTS.md +34 -12
- package/examples/worker/README.md +286 -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 +120 -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 +133 -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,10 @@
|
|
|
1
|
+
// Generated by scripts/generate-providers.mjs; do not edit.
|
|
2
|
+
export const skill = {
|
|
3
|
+
"content": "\n## Identity before routing\n\nThis explicit `surface: \"api\"` connection acts as an internal integration.\nIts `integration_*` tools are canonical for bot-scoped/headless operations.\nHosted MCP is the default and acts as its OAuth-authorized user. Authorization\nis not equivalent: an integration token cannot authorize hosted MCP, and user\nOAuth cannot reproduce the integration bot's ownership/sharing boundary.\nConfigure each under a separate connector id and authorize it independently.\nDo not switch to a user identity to recover a failed integration operation.\n\nUse the bot tools when the task requires that integration identity. Use hosted\n`notion-search`, `notion-fetch`, `notion-get-users`, `notion-get-comments`,\n`notion-create-pages`, `notion-update-page`, and `notion-create-comment` for\nuser-owned content work. Hosted MCP additionally covers sessions, agents,\nattachments and broader workspace operations. REST tool names are not MCP aliases.\n\n\n\n## Databases contain data sources\n\nA Notion database is a container; the rows and the schema live in a *data\nsource* inside it. The two ids are not interchangeable and Notion rejects the\nwrong one.\n\n- The id in a Notion database URL is a **database id**.\n- `integration_get_database` turns it into the `data_sources` list — usually one entry.\n- `integration_get_data_source_schema` and `integration_query_data_source` take that\n **data_source_id**, and so does `integration_create_page` when adding a row.\n\nSo the sequence for \"find rows in this database\" is `integration_get_database` →\n`integration_get_data_source_schema` → `integration_query_data_source`. `integration_search` returns data\nsources directly and skips the first step.\n\n## Property quirks that break writes\n\n- Property names in filters, sorts, and writes must match the schema exactly,\n including case. Read `integration_get_data_source_schema` before composing one.\n- `select` and `status` writes must use an existing option name; inventing\n one fails. The schema lists the valid options.\n- Writes **replace** a property. Sending one item to a `multi_select` or\n `relation` drops the others, so send the complete intended value.\n- `rollup`, `formula`, `unique_id`, and the created/edited fields are\n computed. They cannot be written.\n- A page's title column is rarely called \"title\" — pass `title_property` from\n the schema when creating or updating a row.\n- Notion truncates `title`, `rich_text`, `relation`, and `people` at 25\n entries. `integration_get_page` reports each one in `truncated_properties` as\n `{ name, id }`; pass that `id` as `property_id` to\n `integration_get_page_property` for the complete value.\n\n## Reading page content\n\n`integration_get_page` returns properties. `integration_get_page_content` returns the body as flat\nblocks. Nested blocks (toggles, list children, table rows) need `depth`, and\neach level multiplies requests — a deep read stops at an internal ceiling and\nreports `truncated: true` rather than spending the whole rate-limit budget.\n\n## Appending is append-only\n\n`integration_append_blocks` adds children and nothing else. It cannot move, reorder, or\nreplace an existing block, and a block appended through the API can never be\nrelocated by it afterwards. Get the position right the first time with\n`position` and `after_block_id`. Notion caps one call at 100 blocks.\n\n## Lean by default, raw on request\n\nEvery read projects Notion's payload down to ids, plain text, and flattened\nproperty values. Where the dropped detail can matter — `integration_search`, `integration_get_page`,\n`integration_get_page_content`, `integration_get_page_property`, `integration_get_data_source_schema`,\n`integration_query_data_source`, `integration_list_comments` — pass `raw: true` to get Notion's\nuntouched response instead. It is much larger; reach for it only when a\nspecific field is missing. Narrow `integration_query_data_source` and `integration_get_page` with\n`properties` instead whenever the goal is fewer fields, not more.\n\n`integration_get_page_content` with `raw: true` returns one level exactly as Notion\nsent it and does not walk nested children, so `depth` is ignored alongside\nit. A block type this projection does not model keeps its payload under\n`raw` on the block itself, so nothing silently flattens to an empty string.\n\n## Failures worth reading carefully\n\n- **404** means \"no such object\" *or* \"not shared with this integration\", and\n Notion will not say which. Never conclude a page was deleted from it; check\n that the page is shared with the integration in Notion.\n- **403** is not an expired token. The integration is missing a capability\n (comment capabilities are off by default) or the object was never shared.\n Re-authorizing cannot fix it; an operator must change it in Notion.\n- **429** carries a retry window. Notion allows roughly three requests per\n second per integration, so wait it out rather than retrying immediately.\n\n## No escape hatch\n\nThis connection has no guarded raw-REST tool, deliberately. Notion's public\nAPI is small and slow-moving enough for the named surface to cover it, so\nthere is no `notion_api_*` to reach for — an operation absent from the tool\nlist is absent from this connection, not hidden behind a generic call.\n\n## Writes and pagination\n\n- Notion has **no idempotency key**. A retried `integration_create_page` or\n `integration_add_comment` creates a duplicate. Confirm with `integration_search` before repeating\n a write that may have partially succeeded.\n- List tools take `page_size` (max 100) and return `has_more` with\n `next_cursor`. Pass a cursor back verbatim — it is opaque and must never be\n parsed or constructed. Follow pages inside `execute_code` and reduce there.\n# Notion MCP usage\n\nOfficial MCP interface: tool names, descriptions, argument schemas, and result\nschemas come from Notion's live server. Connecta preserves that catalog and\napplies release-reviewed classification. Reviewed writes stay writes even when Notion claims they only read.\n\nWorkspace purpose: \n\n- This connection acts as its OAuth-authorized user. The separately configured\n `surface: \"api\"` connection retains required internal-integration operations\n under `integration_*` names, including headless content writes, cursor-complete\n queries, exact JSON blocks and property items. No identity fallback occurs.\n- Discover the live catalog before assuming a tool exists. Notion can gate\n tools by workspace, account, client, and rollout independently of Connecta.\n- Start broad discovery with `notion-search`, then use `notion-fetch` on\n the exact page, database, data source, or object before changing it.\n- Use the live input schema as the contract. Notion owns these MCP schemas;\n the REST schemas in Connecta's API interface do not apply to MCP tools with\n similar names.\n- Session and agent tools can launch asynchronous work. Read session state and\n events before sending another message, waiting, or stopping a session.\n- File uploads and attachment tools create durable workspace state. Keep\n downloads inside the requested task and do not expose signed attachment URLs.\n- An `auth_required` failure means this connector's OAuth grant is missing or\n expired. Run `authorize_connector` for this connector id, then retry.\n",
|
|
4
|
+
"instructionsHeading": "Workspace instructions",
|
|
5
|
+
"fragments": {
|
|
6
|
+
"guide_0": "\n## Identity before routing\n\nThis explicit `surface: \"api\"` connection acts as an internal integration.\nIts `integration_*` tools are canonical for bot-scoped/headless operations.\nHosted MCP is the default and acts as its OAuth-authorized user. Authorization\nis not equivalent: an integration token cannot authorize hosted MCP, and user\nOAuth cannot reproduce the integration bot's ownership/sharing boundary.\nConfigure each under a separate connector id and authorize it independently.\nDo not switch to a user identity to recover a failed integration operation.\n\nUse the bot tools when the task requires that integration identity. Use hosted\n`notion-search`, `notion-fetch`, `notion-get-users`, `notion-get-comments`,\n`notion-create-pages`, `notion-update-page`, and `notion-create-comment` for\nuser-owned content work. Hosted MCP additionally covers sessions, agents,\nattachments and broader workspace operations. REST tool names are not MCP aliases.\n\n\n\n## Databases contain data sources\n\nA Notion database is a container; the rows and the schema live in a *data\nsource* inside it. The two ids are not interchangeable and Notion rejects the\nwrong one.\n\n- The id in a Notion database URL is a **database id**.\n- `integration_get_database` turns it into the `data_sources` list — usually one entry.\n- `integration_get_data_source_schema` and `integration_query_data_source` take that\n **data_source_id**, and so does `integration_create_page` when adding a row.\n\nSo the sequence for \"find rows in this database\" is `integration_get_database` →\n`integration_get_data_source_schema` → `integration_query_data_source`. `integration_search` returns data\nsources directly and skips the first step.\n\n## Property quirks that break writes\n\n- Property names in filters, sorts, and writes must match the schema exactly,\n including case. Read `integration_get_data_source_schema` before composing one.\n- `select` and `status` writes must use an existing option name; inventing\n one fails. The schema lists the valid options.\n- Writes **replace** a property. Sending one item to a `multi_select` or\n `relation` drops the others, so send the complete intended value.\n- `rollup`, `formula`, `unique_id`, and the created/edited fields are\n computed. They cannot be written.\n- A page's title column is rarely called \"title\" — pass `title_property` from\n the schema when creating or updating a row.\n- Notion truncates `title`, `rich_text`, `relation`, and `people` at 25\n entries. `integration_get_page` reports each one in `truncated_properties` as\n `{ name, id }`; pass that `id` as `property_id` to\n `integration_get_page_property` for the complete value.\n\n## Reading page content\n\n`integration_get_page` returns properties. `integration_get_page_content` returns the body as flat\nblocks. Nested blocks (toggles, list children, table rows) need `depth`, and\neach level multiplies requests — a deep read stops at an internal ceiling and\nreports `truncated: true` rather than spending the whole rate-limit budget.\n\n## Appending is append-only\n\n`integration_append_blocks` adds children and nothing else. It cannot move, reorder, or\nreplace an existing block, and a block appended through the API can never be\nrelocated by it afterwards. Get the position right the first time with\n`position` and `after_block_id`. Notion caps one call at 100 blocks.\n\n## Lean by default, raw on request\n\nEvery read projects Notion's payload down to ids, plain text, and flattened\nproperty values. Where the dropped detail can matter — `integration_search`, `integration_get_page`,\n`integration_get_page_content`, `integration_get_page_property`, `integration_get_data_source_schema`,\n`integration_query_data_source`, `integration_list_comments` — pass `raw: true` to get Notion's\nuntouched response instead. It is much larger; reach for it only when a\nspecific field is missing. Narrow `integration_query_data_source` and `integration_get_page` with\n`properties` instead whenever the goal is fewer fields, not more.\n\n`integration_get_page_content` with `raw: true` returns one level exactly as Notion\nsent it and does not walk nested children, so `depth` is ignored alongside\nit. A block type this projection does not model keeps its payload under\n`raw` on the block itself, so nothing silently flattens to an empty string.\n\n## Failures worth reading carefully\n\n- **404** means \"no such object\" *or* \"not shared with this integration\", and\n Notion will not say which. Never conclude a page was deleted from it; check\n that the page is shared with the integration in Notion.\n- **403** is not an expired token. The integration is missing a capability\n (comment capabilities are off by default) or the object was never shared.\n Re-authorizing cannot fix it; an operator must change it in Notion.\n- **429** carries a retry window. Notion allows roughly three requests per\n second per integration, so wait it out rather than retrying immediately.\n\n## No escape hatch\n\nThis connection has no guarded raw-REST tool, deliberately. Notion's public\nAPI is small and slow-moving enough for the named surface to cover it, so\nthere is no `notion_api_*` to reach for — an operation absent from the tool\nlist is absent from this connection, not hidden behind a generic call.\n\n## Writes and pagination\n\n- Notion has **no idempotency key**. A retried `integration_create_page` or\n `integration_add_comment` creates a duplicate. Confirm with `integration_search` before repeating\n a write that may have partially succeeded.\n- List tools take `page_size` (max 100) and return `has_more` with\n `next_cursor`. Pass a cursor back verbatim — it is opaque and must never be\n parsed or constructed. Follow pages inside `execute_code` and reduce there.\n",
|
|
7
|
+
"guide_1": "# Notion MCP usage\n\nOfficial MCP interface: tool names, descriptions, argument schemas, and result\nschemas come from Notion's live server. Connecta preserves that catalog and\napplies release-reviewed classification. Reviewed writes stay writes even when Notion claims they only read.\n\nWorkspace purpose: ",
|
|
8
|
+
"guide_2": "\n\n- This connection acts as its OAuth-authorized user. The separately configured\n `surface: \"api\"` connection retains required internal-integration operations\n under `integration_*` names, including headless content writes, cursor-complete\n queries, exact JSON blocks and property items. No identity fallback occurs.\n- Discover the live catalog before assuming a tool exists. Notion can gate\n tools by workspace, account, client, and rollout independently of Connecta.\n- Start broad discovery with `notion-search`, then use `notion-fetch` on\n the exact page, database, data source, or object before changing it.\n- Use the live input schema as the contract. Notion owns these MCP schemas;\n the REST schemas in Connecta's API interface do not apply to MCP tools with\n similar names.\n- Session and agent tools can launch asynchronous work. Read session state and\n events before sending another message, waiting, or stopping a session.\n- File uploads and attachment tools create durable workspace state. Keep\n downloads inside the requested task and do not expose signed attachment URLs.\n- An `auth_required` failure means this connector's OAuth grant is missing or\n expired. Run `authorize_connector` for this connector id, then retry.\n"
|
|
9
|
+
}
|
|
10
|
+
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { ConnectorCallAdmissionPolicy } from "../../types.js";
|
|
2
2
|
/**
|
|
3
3
|
* Overflow's two published environments. They are separate deployments with
|
|
4
4
|
* separate credentials: a staging key works only against staging and a
|
|
@@ -57,4 +57,4 @@ export interface OverflowOptions {
|
|
|
57
57
|
* cannot infer — Overflow's keys carry no recognizable environment marker — so
|
|
58
58
|
* the operator states it, and the title and the guide's first line repeat it.
|
|
59
59
|
*/
|
|
60
|
-
export declare
|
|
60
|
+
export declare const overflow: import("../../provider.js").ProviderFactory<OverflowOptions>;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { skill } from "./skill.generated.js";
|
|
1
2
|
/**
|
|
2
3
|
* Overflow (overflow.co) — church and nonprofit giving: cash, stock, crypto,
|
|
3
4
|
* and donor-advised-fund gifts, the deposits that settle them, the donors who
|
|
@@ -7,7 +8,7 @@
|
|
|
7
8
|
* header-authenticated JSON over thirty-eight operations, so `fetch` through
|
|
8
9
|
* the shared guarded transport keeps this subpath Workers-clean and adds
|
|
9
10
|
* nothing to install. Every tool below is hand-written. Overflow's OpenAPI
|
|
10
|
-
* document is drift evidence only — `
|
|
11
|
+
* document is drift evidence only — `src/providers/overflow/drift.json`
|
|
11
12
|
* records the operations the named tools touch, and
|
|
12
13
|
* `npm run providers:check -- --provider overflow` compares them with the
|
|
13
14
|
* published document without a credential. That document is served only by
|
|
@@ -27,9 +28,12 @@
|
|
|
27
28
|
* exact method, path, and body a human is being asked to allow. Overflow has
|
|
28
29
|
* no upload endpoint, so there is no upload hatch.
|
|
29
30
|
*/
|
|
30
|
-
import { apiConnector as api, defined } from "
|
|
31
|
-
import { guardedFetch, retryAfterMs, } from "
|
|
32
|
-
import { ConnectorCallError } from "
|
|
31
|
+
import { apiConnector as api, defined } from "../../connectors/api-connector.js";
|
|
32
|
+
import { guardedFetch, retryAfterMs, } from "../../connectors/guarded-fetch.js";
|
|
33
|
+
import { ConnectorCallError } from "../../errors.js";
|
|
34
|
+
import { keys, optionsOf } from "../../config-schema.js";
|
|
35
|
+
import { PROVIDER_COMMON } from "../../connectors/option-shapes.js";
|
|
36
|
+
import { asProviderFactory } from "../../provider.js";
|
|
33
37
|
/**
|
|
34
38
|
* Overflow's two published environments. They are separate deployments with
|
|
35
39
|
* separate credentials: a staging key works only against staging and a
|
|
@@ -81,9 +85,7 @@ const OVERFLOW_ADMISSION = {
|
|
|
81
85
|
],
|
|
82
86
|
};
|
|
83
87
|
function asRecord(value) {
|
|
84
|
-
return value && typeof value === "object" && !Array.isArray(value)
|
|
85
|
-
? value
|
|
86
|
-
: {};
|
|
88
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
87
89
|
}
|
|
88
90
|
function asArray(value) {
|
|
89
91
|
return Array.isArray(value) ? value : [];
|
|
@@ -94,9 +96,7 @@ function compact(value) {
|
|
|
94
96
|
/** A `{ id, name }` reference, or undefined when Overflow sent none. */
|
|
95
97
|
function reference(value) {
|
|
96
98
|
const record = asRecord(value);
|
|
97
|
-
return Object.keys(record).length === 0
|
|
98
|
-
? undefined
|
|
99
|
-
: compact({ id: record["id"], name: record["name"] });
|
|
99
|
+
return Object.keys(record).length === 0 ? undefined : compact({ id: record["id"], name: record["name"] });
|
|
100
100
|
}
|
|
101
101
|
// --- Credentials and transport ----------------------------------------------
|
|
102
102
|
const API_KEY_CREDENTIAL = {
|
|
@@ -176,9 +176,7 @@ function windowResetMs(headers) {
|
|
|
176
176
|
if (!raw)
|
|
177
177
|
return undefined;
|
|
178
178
|
const seconds = Number(raw.trim());
|
|
179
|
-
return Number.isFinite(seconds) && seconds >= 0
|
|
180
|
-
? Math.trunc(seconds * 1_000)
|
|
181
|
-
: undefined;
|
|
179
|
+
return Number.isFinite(seconds) && seconds >= 0 ? Math.trunc(seconds * 1_000) : undefined;
|
|
182
180
|
}
|
|
183
181
|
/**
|
|
184
182
|
* Map an Overflow failure by what the caller does next (H11).
|
|
@@ -203,7 +201,7 @@ function overflowFailure(status, headers, payload, method) {
|
|
|
203
201
|
const ambiguity = method !== "GET" && status === 403
|
|
204
202
|
? " Overflow also answers 403 when a donor profile owned by a donor account cannot be edited through the API; if reads succeed with this credential, that refusal is the cause and no credential change will fix it."
|
|
205
203
|
: "";
|
|
206
|
-
return new ConnectorCallError("auth_required", `Overflow rejected the request (HTTP ${status}): ${detail} The client id and API key may be wrong, revoked, or issued for the other environment (staging and production credentials are not interchangeable); an operator must
|
|
204
|
+
return new ConnectorCallError(status === 403 ? "provider_permission_denied" : "auth_required", `Overflow rejected the request (HTTP ${status}): ${detail} The client id and API key may be wrong, revoked, or issued for the other environment (staging and production credentials are not interchangeable); an operator must check them and ask the account administrator to grant resource access if they are valid.${ambiguity}`);
|
|
207
205
|
}
|
|
208
206
|
if (status === 404) {
|
|
209
207
|
return new ConnectorCallError("not_found", `Overflow found no such resource for this nonprofit (HTTP 404): ${detail} Re-resolve the id with its list tool; for a raw call, confirm the path below /api/v3.`);
|
|
@@ -221,7 +219,9 @@ function overflowFailure(status, headers, payload, method) {
|
|
|
221
219
|
const wait = windowResetMs(headers);
|
|
222
220
|
return new ConnectorCallError("unavailable", `Overflow is failing upstream (HTTP ${status}): ${detail}`, wait === undefined ? {} : { retryAfterMs: wait });
|
|
223
221
|
}
|
|
224
|
-
return new ConnectorCallError("connector_call_failed", `Overflow request failed (HTTP ${status}): ${detail}`, {
|
|
222
|
+
return new ConnectorCallError("connector_call_failed", `Overflow request failed (HTTP ${status}): ${detail}`, {
|
|
223
|
+
retryable: false,
|
|
224
|
+
});
|
|
225
225
|
}
|
|
226
226
|
function parseBody(text) {
|
|
227
227
|
if (!text.trim())
|
|
@@ -311,9 +311,7 @@ function projectContribution(value) {
|
|
|
311
311
|
stocks: Object.keys(stocks).length === 0
|
|
312
312
|
? undefined
|
|
313
313
|
: compact({ quantity: stocks["quantity"], tickers: stocks["tickers"] }),
|
|
314
|
-
crypto: Object.keys(crypto).length === 0
|
|
315
|
-
? undefined
|
|
316
|
-
: compact({ quantity: crypto["quantity"], token: crypto["token"] }),
|
|
314
|
+
crypto: Object.keys(crypto).length === 0 ? undefined : compact({ quantity: crypto["quantity"], token: crypto["token"] }),
|
|
317
315
|
dedication: contribution["dedication"] ?? undefined,
|
|
318
316
|
donorNotes: contribution["donorNotes"] ?? undefined,
|
|
319
317
|
metadata: contribution["metadata"] ?? undefined,
|
|
@@ -329,7 +327,7 @@ function projectDonor(value, full) {
|
|
|
329
327
|
lastName: donor["lastName"],
|
|
330
328
|
email: donor["email"],
|
|
331
329
|
phone: full ? donor["phone"] : undefined,
|
|
332
|
-
address: full ? donor["address"] ?? undefined : undefined,
|
|
330
|
+
address: full ? (donor["address"] ?? undefined) : undefined,
|
|
333
331
|
locationIds: donor["locationIds"],
|
|
334
332
|
totalContributionsCount: donor["totalContributionsCount"],
|
|
335
333
|
activeRecurringCount: donor["activeRecurringCount"],
|
|
@@ -444,7 +442,9 @@ function projectPaymentMethod(value) {
|
|
|
444
442
|
function projectCampaign(value) {
|
|
445
443
|
const campaign = asRecord(value);
|
|
446
444
|
const refs = (list) => {
|
|
447
|
-
const rows = asArray(list)
|
|
445
|
+
const rows = asArray(list)
|
|
446
|
+
.map(reference)
|
|
447
|
+
.filter((row) => row !== undefined);
|
|
448
448
|
return rows.length === 0 ? undefined : rows;
|
|
449
449
|
};
|
|
450
450
|
return compact({
|
|
@@ -840,10 +840,7 @@ function rawQuery(value) {
|
|
|
840
840
|
(query[name] ??= []).push(item);
|
|
841
841
|
}
|
|
842
842
|
}
|
|
843
|
-
return Object.fromEntries(Object.entries(query).map(([name, values]) => [
|
|
844
|
-
name,
|
|
845
|
-
values.length === 1 ? values[0] : values,
|
|
846
|
-
]));
|
|
843
|
+
return Object.fromEntries(Object.entries(query).map(([name, values]) => [name, values.length === 1 ? values[0] : values]));
|
|
847
844
|
}
|
|
848
845
|
function tools(send, defaultPageSize) {
|
|
849
846
|
const readOnly = { readOnlyHint: true };
|
|
@@ -864,7 +861,9 @@ function tools(send, defaultPageSize) {
|
|
|
864
861
|
const payload = await callOverflow(send, { method: "GET", path }, ctx);
|
|
865
862
|
const record = asRecord(payload)["data"];
|
|
866
863
|
if (record === undefined || record === null) {
|
|
867
|
-
throw new ConnectorCallError("connector_call_failed", "Overflow answered without the requested record.", {
|
|
864
|
+
throw new ConnectorCallError("connector_call_failed", "Overflow answered without the requested record.", {
|
|
865
|
+
retryable: false,
|
|
866
|
+
});
|
|
868
867
|
}
|
|
869
868
|
return asRecord(record);
|
|
870
869
|
}
|
|
@@ -930,7 +929,11 @@ function tools(send, defaultPageSize) {
|
|
|
930
929
|
type: "array",
|
|
931
930
|
minItems: 1,
|
|
932
931
|
uniqueItems: true,
|
|
933
|
-
items: {
|
|
932
|
+
items: {
|
|
933
|
+
type: "string",
|
|
934
|
+
enum: ["PENDING", "CONFIRMED", "FAILED", "CANCELED"],
|
|
935
|
+
description: "Status bucket.",
|
|
936
|
+
},
|
|
934
937
|
description: "Overflow's coarse status buckets; matches any.",
|
|
935
938
|
},
|
|
936
939
|
campaignId: idProperty("list_campaigns"),
|
|
@@ -966,7 +969,9 @@ function tools(send, defaultPageSize) {
|
|
|
966
969
|
name: "get_contribution",
|
|
967
970
|
description: "Get one contribution by id with its status, amount, campaign, deposit, and donor name. Refunds and chargebacks are separate lists.",
|
|
968
971
|
annotations: readOnly,
|
|
969
|
-
inputSchema: namedInput({ contributionId: idProperty("list_contributions"), raw: RAW_PROPERTY }, [
|
|
972
|
+
inputSchema: namedInput({ contributionId: idProperty("list_contributions"), raw: RAW_PROPERTY }, [
|
|
973
|
+
"contributionId",
|
|
974
|
+
]),
|
|
970
975
|
outputSchema: CONTRIBUTION_SCHEMA,
|
|
971
976
|
handler: async (args, ctx) => {
|
|
972
977
|
const record = await one(`/contributions/${segment(args["contributionId"])}`, ctx);
|
|
@@ -1189,9 +1194,7 @@ function tools(send, defaultPageSize) {
|
|
|
1189
1194
|
outputSchema: listOutput("subscriptions", SUBSCRIPTION_SCHEMA),
|
|
1190
1195
|
handler: (args, ctx) => list({
|
|
1191
1196
|
args,
|
|
1192
|
-
path: args["donorId"] === undefined
|
|
1193
|
-
? "/subscriptions"
|
|
1194
|
-
: `/subscriptions/${segment(args["donorId"])}`,
|
|
1197
|
+
path: args["donorId"] === undefined ? "/subscriptions" : `/subscriptions/${segment(args["donorId"])}`,
|
|
1195
1198
|
key: "subscriptions",
|
|
1196
1199
|
project: projectSubscription,
|
|
1197
1200
|
query: {
|
|
@@ -1240,7 +1243,15 @@ function tools(send, defaultPageSize) {
|
|
|
1240
1243
|
excludeInactive: { type: "boolean", description: "Exclude campaigns that have ended." },
|
|
1241
1244
|
sortBy: {
|
|
1242
1245
|
type: "string",
|
|
1243
|
-
enum: [
|
|
1246
|
+
enum: [
|
|
1247
|
+
"startDate",
|
|
1248
|
+
"endDate",
|
|
1249
|
+
"name",
|
|
1250
|
+
"displayOrder",
|
|
1251
|
+
"totalContributionCount",
|
|
1252
|
+
"totalContributionValue",
|
|
1253
|
+
"uniqueDonorCount",
|
|
1254
|
+
],
|
|
1244
1255
|
description: "Sort field. Defaults to startDate.",
|
|
1245
1256
|
},
|
|
1246
1257
|
sortDirection: { ...SORT_DIRECTION, description: "Defaults to DESC." },
|
|
@@ -1256,7 +1267,9 @@ function tools(send, defaultPageSize) {
|
|
|
1256
1267
|
project: projectCampaign,
|
|
1257
1268
|
query: {
|
|
1258
1269
|
isSubcampaign: args["isSubcampaign"] === undefined
|
|
1259
|
-
? args["parentCampaignId"] === undefined
|
|
1270
|
+
? args["parentCampaignId"] === undefined
|
|
1271
|
+
? undefined
|
|
1272
|
+
: "true"
|
|
1260
1273
|
: String(args["isSubcampaign"]),
|
|
1261
1274
|
parentCampaignId: args["parentCampaignId"],
|
|
1262
1275
|
search: args["search"],
|
|
@@ -1273,7 +1286,11 @@ function tools(send, defaultPageSize) {
|
|
|
1273
1286
|
annotations: readOnly,
|
|
1274
1287
|
inputSchema: namedInput({
|
|
1275
1288
|
includeArchived: { type: "boolean", description: "Include archived locations." },
|
|
1276
|
-
sortBy: {
|
|
1289
|
+
sortBy: {
|
|
1290
|
+
type: "string",
|
|
1291
|
+
enum: ["displayOrder", "name", "createdAt"],
|
|
1292
|
+
description: "Sort field. Defaults to displayOrder.",
|
|
1293
|
+
},
|
|
1277
1294
|
sortDirection: { ...SORT_DIRECTION, description: "Defaults to ASC." },
|
|
1278
1295
|
page: PAGE_PROPERTY,
|
|
1279
1296
|
limit: LIMIT,
|
|
@@ -1395,9 +1412,7 @@ function tools(send, defaultPageSize) {
|
|
|
1395
1412
|
const next = info["nextCursor"];
|
|
1396
1413
|
return compact({
|
|
1397
1414
|
attempts: args["raw"] === true ? rows : rows.map(projectEventLog),
|
|
1398
|
-
nextCursor: info["hasNextPage"] === true && typeof next === "string" && next !== ""
|
|
1399
|
-
? next
|
|
1400
|
-
: undefined,
|
|
1415
|
+
nextCursor: info["hasNextPage"] === true && typeof next === "string" && next !== "" ? next : undefined,
|
|
1401
1416
|
});
|
|
1402
1417
|
},
|
|
1403
1418
|
},
|
|
@@ -1413,78 +1428,14 @@ function usageGuide(purpose, environment, instructions) {
|
|
|
1413
1428
|
|
|
1414
1429
|
${environmentLine}
|
|
1415
1430
|
|
|
1416
|
-
Nonprofit purpose: ${purpose}
|
|
1417
|
-
|
|
1418
|
-
## Money, units, and status
|
|
1419
|
-
|
|
1420
|
-
Overflow does not use one money unit, so read the unit per field:
|
|
1421
|
-
|
|
1422
|
-
- Fields named \`…InCents\` are cents: deposits and their line items and
|
|
1423
|
-
totals, refunds, chargebacks, and the authorize body.
|
|
1424
|
-
- Recurring-gift \`amount\` is dollars: Overflow's create and update bodies
|
|
1425
|
-
say so, and its subscription reads carry the same field.
|
|
1426
|
-
- Contribution \`amount\` states no unit in Overflow's schema. Check one known
|
|
1427
|
-
gift before reporting totals.
|
|
1428
|
-
- \`status\` is per asset type. A gift is final at \`PAID_OUT\` (cash),
|
|
1429
|
-
\`CONFIRMED\` (manual cash, crypto), \`CONTRIBUTION_RECEIVED\` or \`BILLED\`
|
|
1430
|
-
(stock), and \`CONTRIBUTION_RECEIVED\` (DAF). \`statusBucket\` filters by
|
|
1431
|
-
Overflow's coarser PENDING / CONFIRMED / FAILED / CANCELED.
|
|
1432
|
-
- There is no funds endpoint. A gift reports its campaign and subcampaign;
|
|
1433
|
-
\`fundId\` and \`subFundId\` appear only in the payment-authorize body.
|
|
1434
|
-
- Poll for changes with \`minimumUpdatedDate\`; \`minimumInitiatedDate\` is
|
|
1435
|
-
when the donor gave.
|
|
1436
|
-
|
|
1437
|
-
## Reconcile a deposit
|
|
1438
|
-
|
|
1439
|
-
\`list_deposits\` → \`get_deposit_summary\` for totals → \`get_deposit\` for the
|
|
1440
|
-
line items, whose \`referenceId\` names the contribution, refund, or
|
|
1441
|
-
chargeback. Contributions also carry their \`depositId\`.
|
|
1442
|
-
|
|
1443
|
-
## Donor data is sensitive
|
|
1444
|
-
|
|
1445
|
-
Giving history and donor contact details are personal data. Reduce inside
|
|
1446
|
-
\`execute_code\` — aggregate, count, or keep ids — and return names, emails,
|
|
1447
|
-
phones, or addresses only when the task needs them. Lists and contributions
|
|
1448
|
-
already omit contact details; \`get_donor\` is the deliberate lookup.
|
|
1449
|
-
|
|
1450
|
-
## Writes go through \`overflow_api_mutate\`
|
|
1451
|
-
|
|
1452
|
-
Every Overflow write moves money or changes a donor record, so none has a
|
|
1453
|
-
named tool. Each is one approval-gated \`overflow_api_mutate\` call with
|
|
1454
|
-
Overflow's documented body:
|
|
1455
|
-
|
|
1456
|
-
- \`POST /contributions\` charges a saved payment method. Its \`amount\`
|
|
1457
|
-
states no unit; confirm it against a known gift of the same donor before
|
|
1458
|
-
charging. \`POST /payments/authorize\` takes \`amountInCents\` and
|
|
1459
|
-
authorizes a new method (\`0\` only saves it).
|
|
1460
|
-
- \`POST /contributions/{id}/initiate-refund\` (under $1,000 only).
|
|
1461
|
-
- \`POST\` / \`PATCH\` / \`DELETE /subscriptions/{donorId}[/{subscriptionId}]\`
|
|
1462
|
-
creates, changes, or cancels a recurring gift. Its \`amount\` is dollars,
|
|
1463
|
-
not cents: a $50.00 monthly gift is \`amount: 50\`. Cancel takes a
|
|
1464
|
-
\`cancellationReason\` body.
|
|
1465
|
-
- \`POST /donors\`, \`PATCH /donors/{id}\`.
|
|
1466
|
-
|
|
1467
|
-
Resolve every id first — donors, payment methods (\`list_payment_methods\`),
|
|
1468
|
-
campaigns, locations — and never guess one. A write that fails with HTTP 5xx
|
|
1469
|
-
may still have happened: read before retrying.
|
|
1470
|
-
|
|
1471
|
-
## Hatches, pages, and limits
|
|
1472
|
-
|
|
1473
|
-
- \`overflow_api_get\` reaches the reads without a named tool: single refunds,
|
|
1474
|
-
chargebacks, campaigns, locations, webhooks, and recurring gifts
|
|
1475
|
-
(\`/subscriptions/{donorId}/{id}\`), and Tap devices, groups, and
|
|
1476
|
-
destinations (\`/tap/devices\`, \`/tap/groups\`, \`/tap/destinations\`). Paths
|
|
1477
|
-
are below \`/api/v3\`; array filters repeat a \`name[]\` query pair.
|
|
1478
|
-
- Lists page by number: pass \`page\` while \`page.hasMore\` is true.
|
|
1479
|
-
\`list_webhook_event_logs\` pages by cursor instead.
|
|
1480
|
-
- Overflow allows 120 requests per minute per API client. This connection
|
|
1481
|
-
admits the same per runtime, four at a time, which approximates rather than
|
|
1482
|
-
enforces it; a \`rate_limited\` failure carries the wait.
|
|
1483
|
-
${accountInstructions
|
|
1484
|
-
? `\n## Nonprofit instructions\n\n${accountInstructions}\n`
|
|
1485
|
-
: ""}`;
|
|
1431
|
+
Nonprofit purpose: ${purpose}${skill.fragments.guide_0}${accountInstructions ? `\n## ${skill.instructionsHeading}\n\n${accountInstructions}\n` : ""}`;
|
|
1486
1432
|
}
|
|
1487
1433
|
// --- Construction --------------------------------------------------------------
|
|
1434
|
+
/** The closed options overflow() accepts; see `assertKnownOptions`. */
|
|
1435
|
+
const OVERFLOW_OPTIONS = optionsOf()({
|
|
1436
|
+
...PROVIDER_COMMON,
|
|
1437
|
+
...keys("environment", "defaultPageSize", "baseUrl"),
|
|
1438
|
+
});
|
|
1488
1439
|
/**
|
|
1489
1440
|
* A maintained Overflow connection.
|
|
1490
1441
|
*
|
|
@@ -1501,7 +1452,21 @@ ${accountInstructions
|
|
|
1501
1452
|
* cannot infer — Overflow's keys carry no recognizable environment marker — so
|
|
1502
1453
|
* the operator states it, and the title and the guide's first line repeat it.
|
|
1503
1454
|
*/
|
|
1504
|
-
export
|
|
1455
|
+
export const overflow = asProviderFactory({
|
|
1456
|
+
name: "overflow",
|
|
1457
|
+
title: "Overflow",
|
|
1458
|
+
kind: "api",
|
|
1459
|
+
readme: "Overflow",
|
|
1460
|
+
bundle: {
|
|
1461
|
+
"baselineGzip": 20410,
|
|
1462
|
+
"maxGzip": 80410,
|
|
1463
|
+
"note": "./providers/overflow starts at 20,410 B gzip: a hand-written api() surface over the guarded transport with no hosted-MCP interface, so it pulls in neither remoteMcp nor the Effect core the other providers carry. The cap uses the existing baseline + 60,000 B policy.",
|
|
1464
|
+
},
|
|
1465
|
+
skill,
|
|
1466
|
+
options: OVERFLOW_OPTIONS,
|
|
1467
|
+
create: overflowConnector,
|
|
1468
|
+
});
|
|
1469
|
+
function overflowConnector(id, options) {
|
|
1505
1470
|
const purpose = options.purpose?.trim();
|
|
1506
1471
|
if (!purpose) {
|
|
1507
1472
|
throw new Error("overflow() requires a non-empty nonprofit purpose.");
|
|
@@ -1511,9 +1476,7 @@ export function overflow(id, options) {
|
|
|
1511
1476
|
throw new Error('overflow() requires environment: "production" or "staging". Overflow issues separate credentials for each, and connecta will not guess which one a deployment means.');
|
|
1512
1477
|
}
|
|
1513
1478
|
const defaultPageSize = options.defaultPageSize ?? DEFAULT_PAGE_SIZE;
|
|
1514
|
-
if (!Number.isInteger(defaultPageSize) ||
|
|
1515
|
-
defaultPageSize < 1 ||
|
|
1516
|
-
defaultPageSize > MAX_PAGE_SIZE) {
|
|
1479
|
+
if (!Number.isInteger(defaultPageSize) || defaultPageSize < 1 || defaultPageSize > MAX_PAGE_SIZE) {
|
|
1517
1480
|
throw new Error(`overflow() defaultPageSize must be a whole number between 1 and ${MAX_PAGE_SIZE}.`);
|
|
1518
1481
|
}
|
|
1519
1482
|
const send = overflowTransport(options.baseUrl?.trim() || OVERFLOW_API_BASE_URLS[environment]);
|
|
@@ -1533,7 +1496,7 @@ export function overflow(id, options) {
|
|
|
1533
1496
|
const payload = asRecord(await callOverflow(send, { method: "GET", path: "/locations", query: { limit: 1, sortBy: "displayOrder" } }, {
|
|
1534
1497
|
...ctx,
|
|
1535
1498
|
credential: {
|
|
1536
|
-
get: async (field) => (field ? values[field] ?? null : null),
|
|
1499
|
+
get: async (field) => (field ? (values[field] ?? null) : null),
|
|
1537
1500
|
getAll: async () => values,
|
|
1538
1501
|
},
|
|
1539
1502
|
}));
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
// Generated by scripts/generate-providers.mjs; do not edit.
|
|
2
|
+
export const skill = {
|
|
3
|
+
"content": "\n\n## Money, units, and status\n\nOverflow does not use one money unit, so read the unit per field:\n\n- Fields named `…InCents` are cents: deposits and their line items and\n totals, refunds, chargebacks, and the authorize body.\n- Recurring-gift `amount` is dollars: Overflow's create and update bodies\n say so, and its subscription reads carry the same field.\n- Contribution `amount` states no unit in Overflow's schema. Check one known\n gift before reporting totals.\n- `status` is per asset type. A gift is final at `PAID_OUT` (cash),\n `CONFIRMED` (manual cash, crypto), `CONTRIBUTION_RECEIVED` or `BILLED`\n (stock), and `CONTRIBUTION_RECEIVED` (DAF). `statusBucket` filters by\n Overflow's coarser PENDING / CONFIRMED / FAILED / CANCELED.\n- There is no funds endpoint. A gift reports its campaign and subcampaign;\n `fundId` and `subFundId` appear only in the payment-authorize body.\n- Poll for changes with `minimumUpdatedDate`; `minimumInitiatedDate` is\n when the donor gave.\n\n## Reconcile a deposit\n\n`list_deposits` → `get_deposit_summary` for totals → `get_deposit` for the\nline items, whose `referenceId` names the contribution, refund, or\nchargeback. Contributions also carry their `depositId`.\n\n## Donor data is sensitive\n\nGiving history and donor contact details are personal data. Reduce inside\n`execute_code` — aggregate, count, or keep ids — and return names, emails,\nphones, or addresses only when the task needs them. Lists and contributions\nalready omit contact details; `get_donor` is the deliberate lookup.\n\n## Writes go through `overflow_api_mutate`\n\nEvery Overflow write moves money or changes a donor record, so none has a\nnamed tool. Each is one approval-gated `overflow_api_mutate` call with\nOverflow's documented body:\n\n- `POST /contributions` charges a saved payment method. Its `amount`\n states no unit; confirm it against a known gift of the same donor before\n charging. `POST /payments/authorize` takes `amountInCents` and\n authorizes a new method (`0` only saves it).\n- `POST /contributions/{id}/initiate-refund` (under $1,000 only).\n- `POST` / `PATCH` / `DELETE /subscriptions/{donorId}[/{subscriptionId}]`\n creates, changes, or cancels a recurring gift. Its `amount` is dollars,\n not cents: a $50.00 monthly gift is `amount: 50`. Cancel takes a\n `cancellationReason` body.\n- `POST /donors`, `PATCH /donors/{id}`.\n\nResolve every id first — donors, payment methods (`list_payment_methods`),\ncampaigns, locations — and never guess one. A write that fails with HTTP 5xx\nmay still have happened: read before retrying.\n\n## Hatches, pages, and limits\n\n- `overflow_api_get` reaches the reads without a named tool: single refunds,\n chargebacks, campaigns, locations, webhooks, and recurring gifts\n (`/subscriptions/{donorId}/{id}`), and Tap devices, groups, and\n destinations (`/tap/devices`, `/tap/groups`, `/tap/destinations`). Paths\n are below `/api/v3`; array filters repeat a `name[]` query pair.\n- Lists page by number: pass `page` while `page.hasMore` is true.\n `list_webhook_event_logs` pages by cursor instead.\n- Overflow allows 120 requests per minute per API client. This connection\n admits the same per runtime, four at a time, which approximates rather than\n enforces it; a `rate_limited` failure carries the wait.\n",
|
|
4
|
+
"instructionsHeading": "Nonprofit instructions",
|
|
5
|
+
"fragments": {
|
|
6
|
+
"guide_0": "\n\n## Money, units, and status\n\nOverflow does not use one money unit, so read the unit per field:\n\n- Fields named `…InCents` are cents: deposits and their line items and\n totals, refunds, chargebacks, and the authorize body.\n- Recurring-gift `amount` is dollars: Overflow's create and update bodies\n say so, and its subscription reads carry the same field.\n- Contribution `amount` states no unit in Overflow's schema. Check one known\n gift before reporting totals.\n- `status` is per asset type. A gift is final at `PAID_OUT` (cash),\n `CONFIRMED` (manual cash, crypto), `CONTRIBUTION_RECEIVED` or `BILLED`\n (stock), and `CONTRIBUTION_RECEIVED` (DAF). `statusBucket` filters by\n Overflow's coarser PENDING / CONFIRMED / FAILED / CANCELED.\n- There is no funds endpoint. A gift reports its campaign and subcampaign;\n `fundId` and `subFundId` appear only in the payment-authorize body.\n- Poll for changes with `minimumUpdatedDate`; `minimumInitiatedDate` is\n when the donor gave.\n\n## Reconcile a deposit\n\n`list_deposits` → `get_deposit_summary` for totals → `get_deposit` for the\nline items, whose `referenceId` names the contribution, refund, or\nchargeback. Contributions also carry their `depositId`.\n\n## Donor data is sensitive\n\nGiving history and donor contact details are personal data. Reduce inside\n`execute_code` — aggregate, count, or keep ids — and return names, emails,\nphones, or addresses only when the task needs them. Lists and contributions\nalready omit contact details; `get_donor` is the deliberate lookup.\n\n## Writes go through `overflow_api_mutate`\n\nEvery Overflow write moves money or changes a donor record, so none has a\nnamed tool. Each is one approval-gated `overflow_api_mutate` call with\nOverflow's documented body:\n\n- `POST /contributions` charges a saved payment method. Its `amount`\n states no unit; confirm it against a known gift of the same donor before\n charging. `POST /payments/authorize` takes `amountInCents` and\n authorizes a new method (`0` only saves it).\n- `POST /contributions/{id}/initiate-refund` (under $1,000 only).\n- `POST` / `PATCH` / `DELETE /subscriptions/{donorId}[/{subscriptionId}]`\n creates, changes, or cancels a recurring gift. Its `amount` is dollars,\n not cents: a $50.00 monthly gift is `amount: 50`. Cancel takes a\n `cancellationReason` body.\n- `POST /donors`, `PATCH /donors/{id}`.\n\nResolve every id first — donors, payment methods (`list_payment_methods`),\ncampaigns, locations — and never guess one. A write that fails with HTTP 5xx\nmay still have happened: read before retrying.\n\n## Hatches, pages, and limits\n\n- `overflow_api_get` reaches the reads without a named tool: single refunds,\n chargebacks, campaigns, locations, webhooks, and recurring gifts\n (`/subscriptions/{donorId}/{id}`), and Tap devices, groups, and\n destinations (`/tap/devices`, `/tap/groups`, `/tap/destinations`). Paths\n are below `/api/v3`; array filters repeat a `name[]` query pair.\n- Lists page by number: pass `page` while `page.hasMore` is true.\n `list_webhook_event_logs` pages by cursor instead.\n- Overflow allows 120 requests per minute per API client. This connection\n admits the same per runtime, four at a time, which approximates rather than\n enforces it; a `rate_limited` failure carries the wait.\n"
|
|
7
|
+
}
|
|
8
|
+
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { ConnectorCallAdmissionPolicy } from "../../types.js";
|
|
2
2
|
/** Planning Center's REST origin. Override only for a proxy or test double. */
|
|
3
3
|
export declare const PLANNING_CENTER_API_BASE_URL = "https://api.planningcenteronline.com";
|
|
4
4
|
/** The products behind `/<app>/v2`, in the order their guides list them. */
|
|
@@ -56,4 +56,4 @@ export interface PlanningCenterOptions {
|
|
|
56
56
|
baseUrl?: string;
|
|
57
57
|
}
|
|
58
58
|
/** A maintained Planning Center Online connection over the REST API. */
|
|
59
|
-
export declare
|
|
59
|
+
export declare const planningCenter: import("../../provider.js").ProviderFactory<PlanningCenterOptions>;
|