@jskit-ai/connectors-catalog 0.1.1
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/README.md +192 -0
- package/docs/ai-upstream-notices.md +51 -0
- package/docs/ai.md +191 -0
- package/docs/airtable.md +130 -0
- package/docs/algolia.md +190 -0
- package/docs/amazon-redshift.md +229 -0
- package/docs/amplitude.md +210 -0
- package/docs/apify.md +162 -0
- package/docs/apollo-io.md +200 -0
- package/docs/asana.md +126 -0
- package/docs/ashby.md +188 -0
- package/docs/atlassian.md +224 -0
- package/docs/attention.md +162 -0
- package/docs/aws-athena.md +150 -0
- package/docs/aws-credentials.md +75 -0
- package/docs/aws-s3.md +193 -0
- package/docs/bigquery.md +146 -0
- package/docs/brevo.md +122 -0
- package/docs/calendly.md +158 -0
- package/docs/canva.md +191 -0
- package/docs/chargebee.md +192 -0
- package/docs/clay.md +194 -0
- package/docs/clickhouse.md +242 -0
- package/docs/confidence-exp.md +74 -0
- package/docs/confidence-flags.md +75 -0
- package/docs/confidence-oauth.md +137 -0
- package/docs/contentful.md +123 -0
- package/docs/databricks.md +180 -0
- package/docs/dbt-semantic-layer.md +175 -0
- package/docs/elevenlabs.md +102 -0
- package/docs/figma.md +132 -0
- package/docs/firebase-cloud-messaging.md +262 -0
- package/docs/firecrawl.md +137 -0
- package/docs/fireflies.md +95 -0
- package/docs/fireworks-ai.md +53 -0
- package/docs/gatewayapi.md +113 -0
- package/docs/gemini-enterprise.md +224 -0
- package/docs/github-api.md +133 -0
- package/docs/gitlab-api.md +138 -0
- package/docs/gmail.md +133 -0
- package/docs/gong.md +205 -0
- package/docs/google-ads.md +156 -0
- package/docs/google-analytics.md +202 -0
- package/docs/google-docs.md +105 -0
- package/docs/google-drive.md +108 -0
- package/docs/google-maps-platform.md +208 -0
- package/docs/google-oauth.md +123 -0
- package/docs/google-search-console.md +124 -0
- package/docs/google-sheets.md +94 -0
- package/docs/google-slides.md +95 -0
- package/docs/granola.md +178 -0
- package/docs/hex.md +161 -0
- package/docs/heygen.md +124 -0
- package/docs/hubspot.md +142 -0
- package/docs/incident-io.md +118 -0
- package/docs/inngest.md +178 -0
- package/docs/klipy.md +149 -0
- package/docs/lexware.md +144 -0
- package/docs/lightspeed.md +193 -0
- package/docs/linear.md +137 -0
- package/docs/linkedin.md +196 -0
- package/docs/logo-dev.md +152 -0
- package/docs/mailgun.md +153 -0
- package/docs/mapbox.md +174 -0
- package/docs/microsoft-excel.md +97 -0
- package/docs/microsoft-fabric.md +249 -0
- package/docs/microsoft-oauth.md +143 -0
- package/docs/microsoft-onedrive.md +76 -0
- package/docs/microsoft-onenote.md +75 -0
- package/docs/microsoft-outlook.md +90 -0
- package/docs/microsoft-powerpoint.md +119 -0
- package/docs/microsoft-sharepoint.md +75 -0
- package/docs/microsoft-teams.md +72 -0
- package/docs/microsoft-word.md +119 -0
- package/docs/miro.md +117 -0
- package/docs/n8n.md +169 -0
- package/docs/notion.md +137 -0
- package/docs/oura.md +161 -0
- package/docs/paddle.md +168 -0
- package/docs/perplexity.md +85 -0
- package/docs/pipedrive.md +120 -0
- package/docs/polar.md +63 -0
- package/docs/posthog.md +227 -0
- package/docs/prestashop.md +151 -0
- package/docs/replicate.md +60 -0
- package/docs/resend.md +153 -0
- package/docs/salesforce.md +234 -0
- package/docs/sanity.md +122 -0
- package/docs/semrush.md +276 -0
- package/docs/sentry.md +112 -0
- package/docs/sevdesk.md +107 -0
- package/docs/shopify.md +206 -0
- package/docs/slack.md +257 -0
- package/docs/snowflake.md +271 -0
- package/docs/storyblok.md +130 -0
- package/docs/stripe.md +77 -0
- package/docs/supabase.md +51 -0
- package/docs/tally.md +105 -0
- package/docs/telegram.md +165 -0
- package/docs/tiktok.md +201 -0
- package/docs/twilio.md +284 -0
- package/docs/twitch.md +428 -0
- package/docs/wave.md +440 -0
- package/docs/wix.md +1249 -0
- package/docs/wiz.md +177 -0
- package/docs/woocommerce.md +400 -0
- package/docs/wordpress-com.md +358 -0
- package/docs/wordpress-self-hosted.md +252 -0
- package/docs/workday.md +292 -0
- package/docs/x-twitter.md +188 -0
- package/docs/xero.md +429 -0
- package/docs/zoho-books.md +214 -0
- package/docs/zoho-crm.md +192 -0
- package/package.json +153 -0
- package/patterns/ai-connections/PATTERN.md +84 -0
- package/patterns/ai-connections/example/ai-model.js +11 -0
- package/patterns/ai-connections/example/perplexity-answer.js +29 -0
- package/patterns/api-key-connection/PATTERN.md +368 -0
- package/patterns/api-key-connection/example/connections.js +18 -0
- package/patterns/api-key-connection/example/integrations.json +19 -0
- package/patterns/assistant-mcp/PATTERN.md +110 -0
- package/patterns/assistant-mcp/example/integrations.json +13 -0
- package/patterns/assistant-mcp-oauth/PATTERN.md +235 -0
- package/patterns/assistant-mcp-oauth/example/integrations.json +102 -0
- package/patterns/aws-storage-queries/PATTERN.md +169 -0
- package/patterns/aws-storage-queries/example/formats/data-formats.js +35 -0
- package/patterns/aws-storage-queries/example/formats/package-lock.json +49 -0
- package/patterns/aws-storage-queries/example/formats/package.json +12 -0
- package/patterns/aws-storage-queries/example/formats/verify-formats.mjs +37 -0
- package/patterns/aws-storage-queries/example/integrations.json +38 -0
- package/patterns/aws-storage-queries/example/s3-transfer.js +34 -0
- package/patterns/event-delivery/PATTERN.md +151 -0
- package/patterns/event-delivery/example/integrations.json +17 -0
- package/patterns/firebase-messaging/PATTERN.md +156 -0
- package/patterns/firebase-messaging/example/server/notifications.js +23 -0
- package/patterns/google-ads-search/PATTERN.md +92 -0
- package/patterns/google-ads-search/example/ads-setup.js +25 -0
- package/patterns/oauth-connection/PATTERN.md +724 -0
- package/patterns/oauth-connection/example/integrations.json +20 -0
- package/patterns/paddle-catalogue/PATTERN.md +78 -0
- package/patterns/paddle-catalogue/example/create-products.js +38 -0
- package/patterns/public-image/PATTERN.md +84 -0
- package/patterns/public-image/example/integrations.json +13 -0
- package/patterns/public-image/example/logo-url.js +16 -0
- package/patterns/redshift-queries/PATTERN.md +150 -0
- package/patterns/redshift-queries/example/integrations.json +33 -0
- package/patterns/source-scanning/PATTERN.md +83 -0
- package/patterns/source-scanning/example/source-scanner.js +13 -0
- package/src/client/firebase-cloud-messaging.js +10 -0
- package/src/client/google-analytics.js +72 -0
- package/src/client/google-maps-platform.js +39 -0
- package/src/client/logo-dev.js +36 -0
- package/src/server/ai.js +46 -0
- package/src/server/airtable.js +67 -0
- package/src/server/algolia.js +63 -0
- package/src/server/amazon-redshift.js +96 -0
- package/src/server/amplitude.js +31 -0
- package/src/server/apify.js +68 -0
- package/src/server/apollo-io.js +85 -0
- package/src/server/asana.js +64 -0
- package/src/server/ashby.js +61 -0
- package/src/server/atlassian.js +32 -0
- package/src/server/attention.js +93 -0
- package/src/server/aws-athena.js +82 -0
- package/src/server/aws-s3.js +49 -0
- package/src/server/awsTransport.js +75 -0
- package/src/server/bigquery.js +97 -0
- package/src/server/brevo.js +97 -0
- package/src/server/calendly.js +77 -0
- package/src/server/canva.js +13 -0
- package/src/server/chargebee.js +88 -0
- package/src/server/clay.js +78 -0
- package/src/server/clickhouse.js +66 -0
- package/src/server/confidence.js +29 -0
- package/src/server/contentful.js +40 -0
- package/src/server/databricks.js +55 -0
- package/src/server/dbt-semantic-layer.js +95 -0
- package/src/server/elevenlabs.js +81 -0
- package/src/server/figma.js +24 -0
- package/src/server/firebase-cloud-messaging.js +111 -0
- package/src/server/firecrawl.js +70 -0
- package/src/server/fireflies.js +31 -0
- package/src/server/fireworks-ai.js +16 -0
- package/src/server/gatewayapi.js +48 -0
- package/src/server/gemini-enterprise.js +47 -0
- package/src/server/github-api.js +90 -0
- package/src/server/gitlab-api.js +67 -0
- package/src/server/gmail.js +60 -0
- package/src/server/gong.js +52 -0
- package/src/server/google-ads-search.js +134 -0
- package/src/server/google-ads.js +80 -0
- package/src/server/google-docs.js +36 -0
- package/src/server/google-drive.js +71 -0
- package/src/server/google-maps-platform.js +90 -0
- package/src/server/google-search-console.js +31 -0
- package/src/server/google-sheets.js +60 -0
- package/src/server/google-slides.js +36 -0
- package/src/server/google.js +61 -0
- package/src/server/granola.js +115 -0
- package/src/server/graphqlOperation.js +15 -0
- package/src/server/hex.js +29 -0
- package/src/server/heygen.js +54 -0
- package/src/server/hubspot.js +85 -0
- package/src/server/incident-io.js +68 -0
- package/src/server/inngest.js +86 -0
- package/src/server/jsonOperation.js +34 -0
- package/src/server/klipy.js +34 -0
- package/src/server/lexware.js +59 -0
- package/src/server/lightspeed.js +82 -0
- package/src/server/linear.js +52 -0
- package/src/server/linkedin.js +74 -0
- package/src/server/mailgun.js +76 -0
- package/src/server/mapbox.js +46 -0
- package/src/server/mcpRegistration.js +41 -0
- package/src/server/mcpTransport.js +60 -0
- package/src/server/microsoft-excel.js +67 -0
- package/src/server/microsoft-fabric.js +81 -0
- package/src/server/microsoft-onedrive.js +58 -0
- package/src/server/microsoft-onenote.js +52 -0
- package/src/server/microsoft-outlook.js +58 -0
- package/src/server/microsoft-powerpoint.js +5 -0
- package/src/server/microsoft-sharepoint.js +46 -0
- package/src/server/microsoft-teams.js +29 -0
- package/src/server/microsoft-word.js +5 -0
- package/src/server/microsoft.js +88 -0
- package/src/server/miro.js +29 -0
- package/src/server/n8n.js +78 -0
- package/src/server/notion.js +76 -0
- package/src/server/oura.js +48 -0
- package/src/server/paddle.js +83 -0
- package/src/server/perplexity.js +15 -0
- package/src/server/pipedrive.js +95 -0
- package/src/server/polar.js +20 -0
- package/src/server/posthog.js +44 -0
- package/src/server/prestashop.js +42 -0
- package/src/server/replicate.js +42 -0
- package/src/server/resend.js +93 -0
- package/src/server/salesforce.js +84 -0
- package/src/server/sanity.js +31 -0
- package/src/server/semrush.js +359 -0
- package/src/server/sentry.js +30 -0
- package/src/server/sevdesk.js +20 -0
- package/src/server/shopify.js +99 -0
- package/src/server/slack.js +143 -0
- package/src/server/snowflake.js +139 -0
- package/src/server/storyblok.js +49 -0
- package/src/server/stripe.js +13 -0
- package/src/server/supabase.js +13 -0
- package/src/server/tally.js +78 -0
- package/src/server/telegram.js +55 -0
- package/src/server/tiktok.js +86 -0
- package/src/server/twilio.js +90 -0
- package/src/server/twitch.js +409 -0
- package/src/server/wave.js +520 -0
- package/src/server/wix.js +1048 -0
- package/src/server/wiz.js +117 -0
- package/src/server/woocommerce.js +412 -0
- package/src/server/wordpress-com.js +236 -0
- package/src/server/wordpress-self-hosted.js +134 -0
- package/src/server/workday.js +136 -0
- package/src/server/x-twitter.js +110 -0
- package/src/server/xero.js +397 -0
- package/src/server/zoho-books.js +90 -0
- package/src/server/zoho-crm.js +89 -0
- package/src/server/zohoOAuth.js +21 -0
- package/src/shared/ai-models.json +8049 -0
- package/src/shared/ai.js +63 -0
- package/src/shared/algolia.js +29 -0
- package/src/shared/amazon-redshift.js +51 -0
- package/src/shared/amplitude.js +28 -0
- package/src/shared/atlassian.js +43 -0
- package/src/shared/aws.js +72 -0
- package/src/shared/canva.js +66 -0
- package/src/shared/chargebee.js +26 -0
- package/src/shared/clickhouse.js +38 -0
- package/src/shared/confidence.js +28 -0
- package/src/shared/databricks.js +33 -0
- package/src/shared/dbt-semantic-layer.js +32 -0
- package/src/shared/definitions.js +140 -0
- package/src/shared/figma.js +21 -0
- package/src/shared/firebase-cloud-messaging.js +45 -0
- package/src/shared/gemini-enterprise.js +33 -0
- package/src/shared/gong.js +33 -0
- package/src/shared/google-ads-search.js +31 -0
- package/src/shared/google-ads.js +28 -0
- package/src/shared/google-maps-platform.js +28 -0
- package/src/shared/google.js +133 -0
- package/src/shared/granola.js +25 -0
- package/src/shared/hex.js +28 -0
- package/src/shared/inngest.js +35 -0
- package/src/shared/lightspeed.js +75 -0
- package/src/shared/linkedin.js +27 -0
- package/src/shared/logo-dev.js +21 -0
- package/src/shared/mapbox.js +38 -0
- package/src/shared/mcp.js +92 -0
- package/src/shared/microsoft-fabric.js +47 -0
- package/src/shared/microsoft.js +231 -0
- package/src/shared/miro.js +27 -0
- package/src/shared/oura.js +23 -0
- package/src/shared/posthog.js +33 -0
- package/src/shared/prestashop.js +23 -0
- package/src/shared/salesforce.js +36 -0
- package/src/shared/semrush.js +24 -0
- package/src/shared/shopify.js +51 -0
- package/src/shared/siteUrl.js +12 -0
- package/src/shared/slack.js +88 -0
- package/src/shared/snowflake.js +55 -0
- package/src/shared/tiktok.js +22 -0
- package/src/shared/tokens.js +747 -0
- package/src/shared/twilio.js +41 -0
- package/src/shared/twitch.js +49 -0
- package/src/shared/wave.js +52 -0
- package/src/shared/wix.js +40 -0
- package/src/shared/wiz.js +41 -0
- package/src/shared/wordpress-com.js +30 -0
- package/src/shared/wordpress.js +69 -0
- package/src/shared/workday.js +50 -0
- package/src/shared/x-twitter.js +19 -0
- package/src/shared/xero.js +46 -0
- package/src/shared/zoho-books.js +39 -0
- package/src/shared/zoho-crm.js +43 -0
- package/src/shared/zoho-regions.js +12 -0
- package/test/ai.test.js +136 -0
- package/test/airtable.test.js +125 -0
- package/test/algolia.test.js +207 -0
- package/test/amazon-redshift.test.js +272 -0
- package/test/amplitude.test.js +239 -0
- package/test/apify.test.js +93 -0
- package/test/apollo-io.test.js +125 -0
- package/test/asana.test.js +99 -0
- package/test/ashby.test.js +97 -0
- package/test/atlassian.test.js +249 -0
- package/test/attention.test.js +79 -0
- package/test/aws.test.js +405 -0
- package/test/brevo.test.js +71 -0
- package/test/calendly.test.js +136 -0
- package/test/canva.test.js +258 -0
- package/test/chargebee.test.js +195 -0
- package/test/clickhouse.test.js +278 -0
- package/test/confidence.test.js +205 -0
- package/test/databricks.test.js +253 -0
- package/test/dbt-semantic-layer.test.js +221 -0
- package/test/designMcp.test.js +336 -0
- package/test/elevenlabs.test.js +52 -0
- package/test/firebase-cloud-messaging.test.js +242 -0
- package/test/firecrawl.test.js +66 -0
- package/test/gemini-enterprise.test.js +218 -0
- package/test/github-api.test.js +167 -0
- package/test/gitlab-api.test.js +160 -0
- package/test/gong.test.js +192 -0
- package/test/google-ads.test.js +350 -0
- package/test/google-maps-platform.test.js +191 -0
- package/test/google.test.js +710 -0
- package/test/granola.test.js +240 -0
- package/test/hex.test.js +253 -0
- package/test/heygen.test.js +121 -0
- package/test/hubspot.test.js +103 -0
- package/test/inngest.test.js +219 -0
- package/test/lightspeed.test.js +250 -0
- package/test/linear.test.js +146 -0
- package/test/linkedin.test.js +243 -0
- package/test/logo-dev.test.js +79 -0
- package/test/mailgun.test.js +107 -0
- package/test/mapbox.test.js +181 -0
- package/test/mcp.test.js +227 -0
- package/test/microsoft-fabric.test.js +258 -0
- package/test/microsoft.test.js +554 -0
- package/test/n8nOAuth.test.js +188 -0
- package/test/notionOAuth.test.js +183 -0
- package/test/oura.test.js +211 -0
- package/test/paddleCatalogue.test.js +51 -0
- package/test/paddlePermissions.test.js +101 -0
- package/test/perplexityComposition.test.js +39 -0
- package/test/pipedriveOAuth.test.js +140 -0
- package/test/posthog.test.js +200 -0
- package/test/prestashop.test.js +207 -0
- package/test/resend.test.js +163 -0
- package/test/salesforce.test.js +276 -0
- package/test/semrush.test.js +479 -0
- package/test/sentry.test.js +35 -0
- package/test/shopify.test.js +247 -0
- package/test/slack.test.js +320 -0
- package/test/snowflake.test.js +391 -0
- package/test/tally.test.js +75 -0
- package/test/telegram.test.js +58 -0
- package/test/tiktok.test.js +243 -0
- package/test/tokens.test.js +1079 -0
- package/test/twilio.test.js +221 -0
- package/test/twitch.test.js +573 -0
- package/test/wave.test.js +678 -0
- package/test/wix.test.js +1099 -0
- package/test/wiz.test.js +185 -0
- package/test/wordpress-com.test.js +469 -0
- package/test/wordpress.test.js +660 -0
- package/test/workday.test.js +314 -0
- package/test/x-twitter.test.js +256 -0
- package/test/xero.test.js +700 -0
- package/test/zoho-books.test.js +253 -0
- package/test/zoho-crm.test.js +223 -0
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: connectors/assistant-mcp-oauth
|
|
3
|
+
title: Assistant MCP OAuth with portable files
|
|
4
|
+
summary: Configure assistant OAuth clients, then compose existing state, encrypted file grants and authorized MCP calls.
|
|
5
|
+
keywords: connectors, amplitude, atlassian, canva, figma, miro, hex, confidence, granola, client metadata, mcp, oauth, assistant, cli, files
|
|
6
|
+
requires: @jskit-ai/connectors-core, @jskit-ai/connectors-catalog
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Assistant MCP OAuth with portable files
|
|
10
|
+
|
|
11
|
+
## Use when
|
|
12
|
+
|
|
13
|
+
An assistant host or trusted CLI connects its owner's Amplitude, Atlassian, Canva, Figma, Miro, Hex, Confidence or Granola
|
|
14
|
+
account through OAuth and calls MCP tools under that owner's delegated authority.
|
|
15
|
+
|
|
16
|
+
## Do not use when
|
|
17
|
+
|
|
18
|
+
This is not app-user login, production event ingestion or automatic assistant
|
|
19
|
+
attachment. Canva supports its documented metadata client; do not assume every
|
|
20
|
+
provider supports a client without a secret. Use the provider guide to
|
|
21
|
+
distinguish supported OAuth from the provider's other APIs.
|
|
22
|
+
|
|
23
|
+
## Product decisions
|
|
24
|
+
|
|
25
|
+
Choose the region, callback owner, requested permissions and allowed tool
|
|
26
|
+
operations. The host owns user authentication, argument validation, approvals
|
|
27
|
+
and tool presentation. A discovered tool is not permission to execute it.
|
|
28
|
+
|
|
29
|
+
## Framework APIs
|
|
30
|
+
|
|
31
|
+
For HeyGen, import `heygenProvider` and `registerHeyGenClient` from
|
|
32
|
+
`@jskit-ai/connectors-catalog/server/heygen`. Register the assistant host callback
|
|
33
|
+
once and use OAuth with `openid`, `profile`, `email`. Store credentials through
|
|
34
|
+
Env and compose the existing lifecycle. Verification calls `tools.list`, never
|
|
35
|
+
media generation. Authorize `tools.call` names and arguments explicitly; some
|
|
36
|
+
operations consume credits or delete content. API-key profile/voice operations
|
|
37
|
+
remain separate and cannot use an MCP token. See the HeyGen guide and on-screen
|
|
38
|
+
registration steps; no automatic client registration on Connect is implied.
|
|
39
|
+
|
|
40
|
+
For Granola, import `granolaProvider` and `registerGranolaClient` from
|
|
41
|
+
`@jskit-ai/connectors-catalog/server/granola`. Use an assistant-owned OAuth
|
|
42
|
+
connection with `openid`, `profile`, `email` and `offline_access`. Register the
|
|
43
|
+
host callback once, store the returned secret and callback through Env, then
|
|
44
|
+
use the common authorization lifecycle. Verification calls `tools.list`.
|
|
45
|
+
`tools.call` requires host authorization for the exact name and arguments.
|
|
46
|
+
Granola's API-key mode uses separate REST operations; its key cannot replace
|
|
47
|
+
MCP OAuth. The same provider definition rejects cross-method operations.
|
|
48
|
+
See the Granola guide for provider setup, current plan limits and the explicit
|
|
49
|
+
registration workflow; no automatic DCR-on-connect or EMA support is implied.
|
|
50
|
+
|
|
51
|
+
Import `amplitudeProvider` and `registerAmplitudeClient` from
|
|
52
|
+
`@jskit-ai/connectors-catalog/server/amplitude`. Use the existing
|
|
53
|
+
`oauth-connection` pattern's parser, connection service, environment resolver
|
|
54
|
+
and encrypted file store with `providers: [amplitudeProvider]`.
|
|
55
|
+
For Atlassian, import `atlassianProvider` and `registerAtlassianClient` from
|
|
56
|
+
`@jskit-ai/connectors-catalog/server/atlassian`. Register both providers when
|
|
57
|
+
using their configurations in the example file. For Canva, import
|
|
58
|
+
`canvaProvider` from `@jskit-ai/connectors-catalog/server/canva` and
|
|
59
|
+
`createCanvaClientMetadata` from `@jskit-ai/connectors-catalog/shared`.
|
|
60
|
+
For Figma and Miro, use `figmaProvider`/`registerFigmaClient` and
|
|
61
|
+
`miroProvider`/`registerMiroClient` from the corresponding
|
|
62
|
+
`@jskit-ai/connectors-catalog/server/figma` and `/server/miro` exports.
|
|
63
|
+
|
|
64
|
+
## Example files
|
|
65
|
+
|
|
66
|
+
`example/integrations.json` is the portable configuration, also edited by the
|
|
67
|
+
UI. For Amplitude/Atlassian, replace the Client ID after explicit setup and
|
|
68
|
+
store the client secret and callback in Env. Their registration helper returns
|
|
69
|
+
a secret to the privileged setup caller; never expose it through status UI.
|
|
70
|
+
Canva instead uses its public metadata URL and a callback reference, with no
|
|
71
|
+
client secret. Its metadata builder appears under Variation points.
|
|
72
|
+
|
|
73
|
+
```js
|
|
74
|
+
const client = await registerAmplitudeClient({
|
|
75
|
+
region: "us", clientName: "My assistant", callbackUrl: registeredCallback,
|
|
76
|
+
scopes: ["mcp:read", "offline_access"]
|
|
77
|
+
});
|
|
78
|
+
// Existing host storage persists client.clientSecret securely.
|
|
79
|
+
// The application writes client.clientId into its registration JSON.
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Do this once as an authorized setup operation, not on startup or every consent
|
|
83
|
+
attempt. An interrupted request may already have created a provider client.
|
|
84
|
+
Registration neither creates a provider account nor signs in a user.
|
|
85
|
+
|
|
86
|
+
The `oauth-connection` pattern opens `beginAuthorization`'s URL and handles
|
|
87
|
+
`completeAuthorization` at the registered callback under the same owner.
|
|
88
|
+
Verification only discovers tools. Afterward, apply the `assistant-mcp`
|
|
89
|
+
pattern's exact tool/argument policy before a call:
|
|
90
|
+
|
|
91
|
+
```js
|
|
92
|
+
const result = await connections.invoke({
|
|
93
|
+
context, integrationId: "analytics", operation: "tools.call", signal,
|
|
94
|
+
input: { name: approvedToolName, arguments: approvedArguments }
|
|
95
|
+
});
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
`approvedToolName` and `approvedArguments` must come from the host's validated,
|
|
99
|
+
authorized request. Check `result.isError` before claiming success. Do not turn
|
|
100
|
+
returned descriptions or content into new authority. The provider's project
|
|
101
|
+
permissions still apply even when discovery lists a tool.
|
|
102
|
+
|
|
103
|
+
## Invariants
|
|
104
|
+
|
|
105
|
+
- Amplitude uses the same region for registration, consent, token grants and MCP.
|
|
106
|
+
- Hex uses the selected standard/EU/HIPAA issuer and its distinct `/mcp` resource.
|
|
107
|
+
- Confidence uses separate Flags/Experiments integration grants and paths, with its common `/mcp` OAuth resource.
|
|
108
|
+
- Atlassian uses its v2 resource and issuer; host code never substitutes v1 grants.
|
|
109
|
+
- PKCE/state attempts and refresh grants use the existing file-store owner.
|
|
110
|
+
- The provider's OAuth resource is included in authorization/code/refresh calls.
|
|
111
|
+
- Client secrets and access/refresh tokens never enter the portable JSON.
|
|
112
|
+
- Canva explicitly uses `tokenEndpointAuthMethod: "none"` and no secret field.
|
|
113
|
+
- Read and optional write consent remain distinct; the host authorizes calls.
|
|
114
|
+
- Disconnect/cancellation does not undo previously accepted provider mutations.
|
|
115
|
+
- An operator CLI can use its trusted process identity; a public route cannot.
|
|
116
|
+
|
|
117
|
+
## Variation points
|
|
118
|
+
|
|
119
|
+
Select `eu` for an EU-resident account and register the client at that region's
|
|
120
|
+
endpoint. Add `mcp:write` only for authorized content edits.
|
|
121
|
+
For Atlassian, call `registerAtlassianClient` with `clientName`, `callbackUrl`
|
|
122
|
+
and its product `scopes` (no region). Use the `work` integration in the example,
|
|
123
|
+
request only required product permissions, and authorize site/project arguments.
|
|
124
|
+
The provider targets MCP v2 with a flat tool catalogue; v1 clients/tokens cannot
|
|
125
|
+
be reused. Atlassian's authorization server and MCP resource have distinct
|
|
126
|
+
origins, fixed by the provider. Tool discovery may be empty after reduced consent;
|
|
127
|
+
it does not prove product access.
|
|
128
|
+
|
|
129
|
+
For Canva, the `design` integration uses a hosted client metadata URL. Build its
|
|
130
|
+
public document from the same registration and integration values:
|
|
131
|
+
|
|
132
|
+
```js
|
|
133
|
+
const registration = configuration.registrations.canva;
|
|
134
|
+
const document = createCanvaClientMetadata({
|
|
135
|
+
clientId: registration.clientId,
|
|
136
|
+
clientName: configuration.integrations.design.displayName,
|
|
137
|
+
callbackUrl: await resolveReference(registration.callbackUrlRef)
|
|
138
|
+
});
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
Serve `document` as JSON at exactly `registration.clientId` through the host's
|
|
142
|
+
existing static response. The helper does not deploy or publish anything.
|
|
143
|
+
Canva must approve the callback URL; the provider guide gives the application
|
|
144
|
+
steps. Each owner completes consent. Use `design` as the integration ID in
|
|
145
|
+
connection calls, and validate tool arguments against that owner's content.
|
|
146
|
+
Canva's advertised scope list has no `offline_access`; do not add an invented
|
|
147
|
+
permission. The current provider gives MCP operations a 60-second request budget.
|
|
148
|
+
|
|
149
|
+
For Figma, the `figma-design` example uses its remote server. Obtain Figma client
|
|
150
|
+
approval first, then call `registerFigmaClient({ clientName, callbackUrl })`.
|
|
151
|
+
The helper requests `mcp:connect`; this broad permission can expose write tools.
|
|
152
|
+
Validate file/node arguments and approve the specific call independently.
|
|
153
|
+
Figma's callback includes its issuer; keep that parameter for completion.
|
|
154
|
+
Desktop MCP and REST personal tokens use different mechanisms and are outside
|
|
155
|
+
this fragment.
|
|
156
|
+
|
|
157
|
+
For Miro, use `miro-boards` and call
|
|
158
|
+
`registerMiroClient({ clientName, callbackUrl, scopes: ["boards:read"] })`.
|
|
159
|
+
Consent selects a team. Reconnect deliberately to change it; do not derive team
|
|
160
|
+
authority from a user-supplied board argument. Add `boards:write` only when
|
|
161
|
+
needed and keep exact tool/argument policy in the host. Identity scopes are
|
|
162
|
+
optional and do not implement app login. Neither Figma nor Miro advertises an
|
|
163
|
+
`offline_access` scope in the metadata used by these fragments.
|
|
164
|
+
|
|
165
|
+
For providers advertising it, omitting `offline_access` can require renewed consent when access expires.
|
|
166
|
+
The application chooses the callback route and file state directory through its existing owners.
|
|
167
|
+
|
|
168
|
+
## Verification
|
|
169
|
+
|
|
170
|
+
Provider tests use simulated OAuth/MCP replies and real encrypted temporary
|
|
171
|
+
files. They verify regional/issuer destinations, setup metadata, permissions,
|
|
172
|
+
restart, refresh, isolation and failures. The editor test proves configuration persistence. No
|
|
173
|
+
sample app is generated or live account/tool operation performed.
|
|
174
|
+
|
|
175
|
+
## Avoid
|
|
176
|
+
|
|
177
|
+
Do not register a fresh client on every launch, log the setup result, expose the
|
|
178
|
+
client secret to the browser, or infer permission from a tool's presence in
|
|
179
|
+
discovery. Keep provider content out of the host's authority decisions.
|
|
180
|
+
|
|
181
|
+
## Hex assistant tools
|
|
182
|
+
|
|
183
|
+
Use `hexProvider` and `registerHexClient` from
|
|
184
|
+
`@jskit-ai/connectors-catalog/server/hex`. The guide at `docs/hex.md` supplies
|
|
185
|
+
manual setup, a complete portable configuration and managed-host boundaries.
|
|
186
|
+
Set `settings.endpoint` to `standard`, `eu` or `hipaa`; the same value must be
|
|
187
|
+
used during explicit client registration. Single-tenant Hex URLs need separate
|
|
188
|
+
endpoint support. Never redirect existing credentials to a user-supplied URL.
|
|
189
|
+
|
|
190
|
+
```js
|
|
191
|
+
const client = await registerHexClient({
|
|
192
|
+
endpoint: "eu", clientName: "My assistant", callbackUrl: registeredCallback,
|
|
193
|
+
scopes: ["openid", "profile", "email", "offline_access"]
|
|
194
|
+
});
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
Persist this privileged result through the host's secret/configuration owners,
|
|
198
|
+
then use the common begin/complete OAuth flow. API tokens cannot substitute for
|
|
199
|
+
MCP consent. Identity scopes do not limit tools to reads; authorize each tool
|
|
200
|
+
and argument before calling it. Discover current argument schemas rather than
|
|
201
|
+
inventing `create_thread` or `continue_thread` inputs. Calls can start analysis
|
|
202
|
+
and consume provider credits. Check `isError`, expose progress, and schedule
|
|
203
|
+
bounded follow-up reads explicitly; never replay a Thread creation because a
|
|
204
|
+
response was lost. This fragment does not install tools into an AI automatically
|
|
205
|
+
or use an ID token as an application login session.
|
|
206
|
+
|
|
207
|
+
## Confidence Flags and Experiments
|
|
208
|
+
|
|
209
|
+
Import `confidenceFlagsProvider` from
|
|
210
|
+
`@jskit-ai/connectors-catalog/server/confidence-flags` or
|
|
211
|
+
`confidenceExpProvider` from `/server/confidence-exp`. Both export the explicit
|
|
212
|
+
`registerConfidenceClient` setup helper. The individual `docs/confidence-*.md`
|
|
213
|
+
guides supply portable configurations and link to shared registration steps.
|
|
214
|
+
Register the provider(s) with the same connection service and encrypted file store.
|
|
215
|
+
|
|
216
|
+
```js
|
|
217
|
+
const client = await registerConfidenceClient({
|
|
218
|
+
clientName: "My assistant", callbackUrl: registeredCallback,
|
|
219
|
+
scopes: ["openid", "profile", "email", "offline_access"]
|
|
220
|
+
});
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
Registration is privileged and must not run on every connection. Keep separate
|
|
224
|
+
integration IDs for Flags and Experiments even when they share a client. Their
|
|
225
|
+
OAuth resource is common; that does not authorize another integration's grant.
|
|
226
|
+
The pinned transport must not follow the provider's HTTP discovery challenge.
|
|
227
|
+
The conflicting `flags:read` metadata is documented, not presented as a proven
|
|
228
|
+
permission choice. Identity scopes do not establish read-only tool access.
|
|
229
|
+
|
|
230
|
+
Use discovery schemas and host policy for each exact tool and resource name.
|
|
231
|
+
Flag management tools can mutate targeting and variants; approve their concrete
|
|
232
|
+
inputs before execution and never replay after a lost response. Experiment
|
|
233
|
+
results can carry summaries or detailed data; preserve errors and let the host
|
|
234
|
+
select the desired view. Neither connector installs an OpenFeature evaluator,
|
|
235
|
+
collects events, provisions a warehouse or automatically attaches tools to an AI.
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"registrations": {
|
|
4
|
+
"amplitude": {
|
|
5
|
+
"source": "own",
|
|
6
|
+
"clientId": "assigned-client-id",
|
|
7
|
+
"clientSecretRef": "env:AMPLITUDE_CLIENT_SECRET",
|
|
8
|
+
"callbackUrlRef": "env:AMPLITUDE_CALLBACK_URL"
|
|
9
|
+
},
|
|
10
|
+
"atlassian": {
|
|
11
|
+
"source": "own",
|
|
12
|
+
"clientId": "assigned-v2-client-id",
|
|
13
|
+
"clientSecretRef": "env:ATLASSIAN_CLIENT_SECRET",
|
|
14
|
+
"callbackUrlRef": "env:ATLASSIAN_CALLBACK_URL"
|
|
15
|
+
},
|
|
16
|
+
"canva": {
|
|
17
|
+
"source": "own",
|
|
18
|
+
"clientId": "https://assistant.example/oauth/canva.json",
|
|
19
|
+
"tokenEndpointAuthMethod": "none",
|
|
20
|
+
"callbackUrlRef": "env:CANVA_CALLBACK_URL"
|
|
21
|
+
},
|
|
22
|
+
"figma": {
|
|
23
|
+
"source": "own",
|
|
24
|
+
"clientId": "assigned-client-id",
|
|
25
|
+
"clientSecretRef": "env:FIGMA_CLIENT_SECRET",
|
|
26
|
+
"callbackUrlRef": "env:FIGMA_CALLBACK_URL"
|
|
27
|
+
},
|
|
28
|
+
"miro": {
|
|
29
|
+
"source": "own",
|
|
30
|
+
"clientId": "assigned-client-id",
|
|
31
|
+
"clientSecretRef": "env:MIRO_CLIENT_SECRET",
|
|
32
|
+
"callbackUrlRef": "env:MIRO_CALLBACK_URL"
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
"integrations": {
|
|
36
|
+
"analytics": {
|
|
37
|
+
"provider": "amplitude",
|
|
38
|
+
"accountMode": "assistant",
|
|
39
|
+
"scopes": [
|
|
40
|
+
"mcp:read",
|
|
41
|
+
"offline_access"
|
|
42
|
+
],
|
|
43
|
+
"authentication": {
|
|
44
|
+
"method": "oauth2",
|
|
45
|
+
"registrationRef": "amplitude"
|
|
46
|
+
},
|
|
47
|
+
"settings": {
|
|
48
|
+
"region": "us"
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
"work": {
|
|
52
|
+
"provider": "atlassian",
|
|
53
|
+
"accountMode": "assistant",
|
|
54
|
+
"scopes": [
|
|
55
|
+
"read:me",
|
|
56
|
+
"read:jira:agent-interface",
|
|
57
|
+
"offline_access"
|
|
58
|
+
],
|
|
59
|
+
"authentication": {
|
|
60
|
+
"method": "oauth2",
|
|
61
|
+
"registrationRef": "atlassian"
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
"design": {
|
|
65
|
+
"provider": "canva",
|
|
66
|
+
"displayName": "Design assistant",
|
|
67
|
+
"accountMode": "assistant",
|
|
68
|
+
"scopes": [
|
|
69
|
+
"profile:read",
|
|
70
|
+
"design:meta:read",
|
|
71
|
+
"design:content:read",
|
|
72
|
+
"folder:read"
|
|
73
|
+
],
|
|
74
|
+
"authentication": {
|
|
75
|
+
"method": "oauth2",
|
|
76
|
+
"registrationRef": "canva"
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
"figma-design": {
|
|
80
|
+
"provider": "figma",
|
|
81
|
+
"accountMode": "assistant",
|
|
82
|
+
"scopes": [
|
|
83
|
+
"mcp:connect"
|
|
84
|
+
],
|
|
85
|
+
"authentication": {
|
|
86
|
+
"method": "oauth2",
|
|
87
|
+
"registrationRef": "figma"
|
|
88
|
+
}
|
|
89
|
+
},
|
|
90
|
+
"miro-boards": {
|
|
91
|
+
"provider": "miro",
|
|
92
|
+
"accountMode": "assistant",
|
|
93
|
+
"scopes": [
|
|
94
|
+
"boards:read"
|
|
95
|
+
],
|
|
96
|
+
"authentication": {
|
|
97
|
+
"method": "oauth2",
|
|
98
|
+
"registrationRef": "miro"
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: connectors/aws-storage-queries
|
|
3
|
+
title: AWS object storage and Athena queries with explicit credentials
|
|
4
|
+
summary: Compose signed AWS operations, file configuration and application authorization from CLI or server code.
|
|
5
|
+
keywords: aws, s3, athena, iam, sts, connectors, storage, queries, cli, files
|
|
6
|
+
requires: @jskit-ai/connectors-core, @jskit-ai/connectors-catalog
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# AWS object storage and Athena queries with explicit credentials
|
|
10
|
+
|
|
11
|
+
## Use when
|
|
12
|
+
|
|
13
|
+
An application or an explicitly authorized CLI operator needs objects in one
|
|
14
|
+
S3 bucket, or SQL queries in one Athena workgroup. The package provides the
|
|
15
|
+
runtime: schema validation, SDK signing and response parsing, fixed regional
|
|
16
|
+
origins, file connection storage and operation authorization. AI code only
|
|
17
|
+
composes those libraries with the application's identity and resource policy.
|
|
18
|
+
|
|
19
|
+
## Do not use when
|
|
20
|
+
|
|
21
|
+
Do not use this as an application login, an AWS account creator, a general SDK
|
|
22
|
+
proxy, or proof that a managed Vibe64 allocation exists. Do not use a machine's
|
|
23
|
+
default AWS credentials for arbitrary application users. Per-user federation,
|
|
24
|
+
AWS IAM Identity Center, noncommercial AWS partitions and arbitrary endpoints
|
|
25
|
+
are outside the fragment. Athena statements can write data and incur costs;
|
|
26
|
+
connecting does not approve arbitrary future SQL.
|
|
27
|
+
|
|
28
|
+
## Product decisions
|
|
29
|
+
|
|
30
|
+
Use the exact [S3](https://github.com/mobily-enterprises/jskit-ai/blob/main/packages/connectors-catalog/docs/aws-s3.md) or
|
|
31
|
+
[Athena](https://github.com/mobily-enterprises/jskit-ai/blob/main/packages/connectors-catalog/docs/aws-athena.md) JSON. The same file is usable by CLI and the
|
|
32
|
+
Vibe64 form. Store the actual secret access key, access key ID and optional
|
|
33
|
+
session token outside source. The access key ID uses `settings.accessKeyIdRef`,
|
|
34
|
+
the secret uses `authentication.secretRef`, and temporary credentials add
|
|
35
|
+
`settings.sessionTokenRef`. A missing explicit binding is an error.
|
|
36
|
+
|
|
37
|
+
## Invariants
|
|
38
|
+
|
|
39
|
+
The host resolver must supply a consistent credential set and renew temporary
|
|
40
|
+
STS credentials. It must not give a public application the paid account's
|
|
41
|
+
identity just because that application names a binding. Resource provisioning,
|
|
42
|
+
account assignments, quotas and credential renewal are separate operations.
|
|
43
|
+
There is no OAuth callback for these modes. See
|
|
44
|
+
[AWS ownership](https://github.com/mobily-enterprises/jskit-ai/blob/main/packages/connectors-catalog/docs/aws-credentials.md).
|
|
45
|
+
|
|
46
|
+
## Framework APIs
|
|
47
|
+
|
|
48
|
+
Follow the [API-key connection pattern](../api-key-connection/PATTERN.md) to
|
|
49
|
+
read configuration, construct encrypted file storage and define authorization.
|
|
50
|
+
Register the provider exports needed by that application:
|
|
51
|
+
|
|
52
|
+
```js
|
|
53
|
+
import { awsS3Provider } from "@jskit-ai/connectors-catalog/server/aws-s3";
|
|
54
|
+
import { awsAthenaProvider } from "@jskit-ai/connectors-catalog/server/aws-athena";
|
|
55
|
+
|
|
56
|
+
const providers = [awsS3Provider, awsAthenaProvider];
|
|
57
|
+
// Pass providers, validated configuration, store, resolveReference and authorize
|
|
58
|
+
// to createConnectionService, or compose the ordinary connector Feature.
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Call `service.connectApiKey({context, integrationId})` explicitly. S3 checks a
|
|
62
|
+
ListObjectsV2 page; Athena checks workgroup metadata. Those reads are useful
|
|
63
|
+
verification, not a claim of every object/table permission. API-key
|
|
64
|
+
`grantedScopes` is empty; configured S3 read/write selections only limit local
|
|
65
|
+
operations. IAM and bucket policies still decide access.
|
|
66
|
+
|
|
67
|
+
## Example files
|
|
68
|
+
|
|
69
|
+
[example/integrations.json](example/integrations.json) contains both resource slots.
|
|
70
|
+
The [transfer module](example/s3-transfer.js) composes signed GET/PUT with native
|
|
71
|
+
Fetch. Optional [format composition](example/formats/data-formats.js) uses ordinary
|
|
72
|
+
JSON, CSV and Parquet libraries. Its own package manifest, lockfile and focused
|
|
73
|
+
verification command make those optional application dependencies explicit; they
|
|
74
|
+
are not installed for every connector consumer. See the S3 guide for composition.
|
|
75
|
+
Keep the resource slots in `integrations.json` and these calls in an application-owned server module or CLI command.
|
|
76
|
+
|
|
77
|
+
For S3, authorize the requested prefix/key against the authenticated user before
|
|
78
|
+
invocation. A shared connection does not make the whole bucket public.
|
|
79
|
+
|
|
80
|
+
```js
|
|
81
|
+
const page = await service.invoke({
|
|
82
|
+
context, integrationId: "files", operation: "objects.list",
|
|
83
|
+
input: { prefix: allowedPrefix, maxKeys: 100 }
|
|
84
|
+
});
|
|
85
|
+
const objects = (page.Contents || []).map((object) => ({
|
|
86
|
+
...object,
|
|
87
|
+
Key: page.EncodingType === "url" ? decodeURIComponent(object.Key) : object.Key
|
|
88
|
+
}));
|
|
89
|
+
// NextContinuationToken is opaque: pass it unchanged to the next list call.
|
|
90
|
+
// Authorize the selected decoded key through the same policy before signing.
|
|
91
|
+
const download = await service.invoke({
|
|
92
|
+
context, integrationId: "files", operation: "objects.downloadUrl",
|
|
93
|
+
input: { key: authorizedKey, expiresInSeconds: 300 }
|
|
94
|
+
});
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
`objects.uploadUrl` uses the same key/expiry input and requires configured
|
|
98
|
+
`write`. The result's URL is a temporary bearer credential; return it only to the
|
|
99
|
+
intended caller, without logging it. Transfer with its exact GET/PUT method and
|
|
100
|
+
URL. A PUT body can overwrite that object. Neither signing nor a successful
|
|
101
|
+
connection proves delivery. Keys preserve spaces and literal percent signs;
|
|
102
|
+
never normalize paths. Standalone `.`/`..` segments are intentionally rejected.
|
|
103
|
+
Browser transfers need appropriate bucket CORS for the current app origin.
|
|
104
|
+
|
|
105
|
+
For Athena discovery, invoke `catalogs.list` (optional `maxResults` 2–50 and
|
|
106
|
+
`nextToken`), `databases.list` (`catalog`, optional page fields), then
|
|
107
|
+
`tables.list` (`catalog`, `database`, optional page fields). Database/table pages
|
|
108
|
+
allow 1–50 rows. Preserve returned column and partition types and pass each
|
|
109
|
+
opaque `NextToken` unchanged. Workgroup selection is not catalog isolation:
|
|
110
|
+
authorize the catalog/database and exposed metadata for the current caller.
|
|
111
|
+
These operations require the Athena/Glue permissions listed in the provider
|
|
112
|
+
guide and do not execute SQL or provision a catalog.
|
|
113
|
+
|
|
114
|
+
For Athena, construct or select the exact authorized statement, database and
|
|
115
|
+
catalog on the server. Do not expose an unrestricted `query.start` proxy to
|
|
116
|
+
untrusted users. Bind its logical request token and returned query ID to the
|
|
117
|
+
application owner in the application's own state (files are sufficient).
|
|
118
|
+
|
|
119
|
+
```js
|
|
120
|
+
const started = await service.invoke({
|
|
121
|
+
context, integrationId: "queries", operation: "query.start",
|
|
122
|
+
input: { sql: authorizedSql, clientRequestToken: logicalRequestToken,
|
|
123
|
+
database: authorizedDatabase }
|
|
124
|
+
});
|
|
125
|
+
const status = await service.invoke({
|
|
126
|
+
context, integrationId: "queries", operation: "query.status",
|
|
127
|
+
input: { queryId: started.QueryExecutionId }
|
|
128
|
+
});
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
The token is 32–128 characters and must identify one authorized logical query.
|
|
132
|
+
Reuse it with identical input after an ambiguous start response; the adapter
|
|
133
|
+
never replays automatically. A returned query ID is not completion. When status
|
|
134
|
+
is SUCCEEDED, request `query.results` with that authorized ID and a bounded page
|
|
135
|
+
size. Preserve column types, header rows, empty cells and string values. Pass
|
|
136
|
+
`NextToken` unchanged to retrieve another page.
|
|
137
|
+
|
|
138
|
+
For cancellation, call `query.cancel` with an authorized query ID; then inspect
|
|
139
|
+
status when final cancellation must be known. Aborting a local HTTP request,
|
|
140
|
+
closing the UI or disconnecting does not cancel an AWS query. Before status,
|
|
141
|
+
results or cancellation, the library checks the execution's workgroup. The
|
|
142
|
+
application must still enforce ownership within that workgroup.
|
|
143
|
+
|
|
144
|
+
## Variation points
|
|
145
|
+
|
|
146
|
+
Choose long-lived IAM-user bindings or host-renewed STS bindings. Add S3 write
|
|
147
|
+
only when the application supports uploads. Result storage can be supplied by
|
|
148
|
+
the Athena workgroup or configured in the file; the workgroup can enforce its
|
|
149
|
+
own location. These choices use the same runtime APIs.
|
|
150
|
+
|
|
151
|
+
## Avoid
|
|
152
|
+
|
|
153
|
+
Do not expose presigned URLs in logs, infer table permission from a workgroup
|
|
154
|
+
read, treat workgroup membership as user isolation, or poll queries without an
|
|
155
|
+
application-controlled limit.
|
|
156
|
+
|
|
157
|
+
## Verification
|
|
158
|
+
|
|
159
|
+
Missing credential references fail before HTTP. Expired/rejected AWS credentials
|
|
160
|
+
require renewal and reconnection. Region changes require verification again.
|
|
161
|
+
Permission failures and account throttling are distinct, redacted errors.
|
|
162
|
+
Signing and SDK requests respect the core timeout/cancellation signal and use
|
|
163
|
+
one attempt with no redirects. Never respond to an IAM denial by switching to
|
|
164
|
+
another account or broadening a policy automatically.
|
|
165
|
+
|
|
166
|
+
Use the focused `packages/connectors-catalog/test/aws.test.js` for protocol and
|
|
167
|
+
file-persistence proof. Public editor tests cover portable fields and reload;
|
|
168
|
+
shared-form checks cover responsive composition. No live AWS account, actual
|
|
169
|
+
object transfer, SQL execution or generated app is needed for this test scope.
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { parse } from "csv-parse/sync";
|
|
2
|
+
import { stringify } from "csv-stringify/sync";
|
|
3
|
+
import { parquetReadObjects } from "hyparquet";
|
|
4
|
+
import { parquetWriteBuffer } from "hyparquet-writer";
|
|
5
|
+
|
|
6
|
+
// Application-owned, in-memory composition for bounded files. The format is an
|
|
7
|
+
// explicit application decision, never guessed from an untrusted filename.
|
|
8
|
+
export function encodeDataFile(format, value) {
|
|
9
|
+
if (format === "json") {
|
|
10
|
+
const text = JSON.stringify(value);
|
|
11
|
+
if (text === undefined) throw new TypeError("Supply a JSON-serializable value.");
|
|
12
|
+
return new TextEncoder().encode(text);
|
|
13
|
+
}
|
|
14
|
+
// CSV is an array of row arrays, including any header row. Preserve strings
|
|
15
|
+
// rather than guessing numeric types or discarding leading zeroes.
|
|
16
|
+
if (format === "csv") return new TextEncoder().encode(stringify(value));
|
|
17
|
+
// Parquet requires native columnData: [{ name, type, data }]. The application
|
|
18
|
+
// supplies its explicit schema; do not infer a schema from an empty table.
|
|
19
|
+
if (format === "parquet") return new Uint8Array(parquetWriteBuffer({ columnData: value }));
|
|
20
|
+
throw new TypeError("Choose json, csv or parquet.");
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export async function decodeDataFile(format, bytes, { maxBytes = 8 * 1024 * 1024 } = {}) {
|
|
24
|
+
if (!(bytes instanceof Uint8Array)) throw new TypeError("Supply file bytes as Uint8Array.");
|
|
25
|
+
if (!Number.isSafeInteger(maxBytes) || maxBytes < 1 || bytes.byteLength > maxBytes) {
|
|
26
|
+
throw new RangeError("File exceeds the application's in-memory parsing limit.");
|
|
27
|
+
}
|
|
28
|
+
if (format === "parquet") return parquetReadObjects({
|
|
29
|
+
file: bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength)
|
|
30
|
+
});
|
|
31
|
+
const text = new TextDecoder("utf-8", { fatal: true }).decode(bytes);
|
|
32
|
+
if (format === "json") return JSON.parse(text);
|
|
33
|
+
if (format === "csv") return parse(text, { bom: true });
|
|
34
|
+
throw new TypeError("Choose json, csv or parquet.");
|
|
35
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "s3-native-format-example",
|
|
3
|
+
"lockfileVersion": 3,
|
|
4
|
+
"requires": true,
|
|
5
|
+
"packages": {
|
|
6
|
+
"": {
|
|
7
|
+
"name": "s3-native-format-example",
|
|
8
|
+
"dependencies": {
|
|
9
|
+
"csv-parse": "7.0.2",
|
|
10
|
+
"csv-stringify": "6.8.3",
|
|
11
|
+
"hyparquet": "1.30.1",
|
|
12
|
+
"hyparquet-writer": "0.16.9"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"node_modules/csv-parse": {
|
|
16
|
+
"version": "7.0.2",
|
|
17
|
+
"resolved": "https://registry.npmjs.org/csv-parse/-/csv-parse-7.0.2.tgz",
|
|
18
|
+
"integrity": "sha512-uKZghv9UmPkMVLYy//KZ9HFAIJsl7wkhoEdIL0+rhuSY9pZQlhaeGEDPIe+/w7eh81MOql8Q/9+inAGWG6ZHYA==",
|
|
19
|
+
"license": "MIT"
|
|
20
|
+
},
|
|
21
|
+
"node_modules/csv-stringify": {
|
|
22
|
+
"version": "6.8.3",
|
|
23
|
+
"resolved": "https://registry.npmjs.org/csv-stringify/-/csv-stringify-6.8.3.tgz",
|
|
24
|
+
"integrity": "sha512-gIeSCvq5F4VtXV3naV3VAewLhBkiZBz+PPhTOA8H3Y8h/ELa+R1ml0GZck/4/Nzo9ep2lvOluilJ6MJlbZsKMA==",
|
|
25
|
+
"license": "MIT"
|
|
26
|
+
},
|
|
27
|
+
"node_modules/hyparquet": {
|
|
28
|
+
"version": "1.30.1",
|
|
29
|
+
"resolved": "https://registry.npmjs.org/hyparquet/-/hyparquet-1.30.1.tgz",
|
|
30
|
+
"integrity": "sha512-307mnGbxzx0nXPGTV6Mhp10gKIu6t+NhvBQJF+PVQsHA295sqznlVOqEAH+fohH2Rqx7NV0Myh9rmuM9E9Ch+w==",
|
|
31
|
+
"license": "MIT"
|
|
32
|
+
},
|
|
33
|
+
"node_modules/hyparquet-writer": {
|
|
34
|
+
"version": "0.16.9",
|
|
35
|
+
"resolved": "https://registry.npmjs.org/hyparquet-writer/-/hyparquet-writer-0.16.9.tgz",
|
|
36
|
+
"integrity": "sha512-VZvH4Vq9lQwZa/+1y4YrEwF9+FAe5pED+mVN4AHflCoFk5LG2RemMHW9iwVlVqug7fO3ATwEMSG68cr3uZAkjQ==",
|
|
37
|
+
"license": "MIT",
|
|
38
|
+
"dependencies": {
|
|
39
|
+
"hyparquet": "1.29.2"
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
"node_modules/hyparquet-writer/node_modules/hyparquet": {
|
|
43
|
+
"version": "1.29.2",
|
|
44
|
+
"resolved": "https://registry.npmjs.org/hyparquet/-/hyparquet-1.29.2.tgz",
|
|
45
|
+
"integrity": "sha512-2LxinZ8X0JqToST+9OXcy9t3t5Q7ZneMTkSqUx/36Hv18pCTk/N71IWZc7APTSNG1Me39l/jjEvzZSZ0R+Knbw==",
|
|
46
|
+
"license": "MIT"
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "s3-native-format-example",
|
|
3
|
+
"private": true,
|
|
4
|
+
"type": "module",
|
|
5
|
+
"scripts": { "test": "node --test --test-concurrency=1 verify-formats.mjs" },
|
|
6
|
+
"dependencies": {
|
|
7
|
+
"csv-parse": "7.0.2",
|
|
8
|
+
"csv-stringify": "6.8.3",
|
|
9
|
+
"hyparquet": "1.30.1",
|
|
10
|
+
"hyparquet-writer": "0.16.9"
|
|
11
|
+
}
|
|
12
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import test from "node:test";
|
|
3
|
+
import { encodeDataFile, decodeDataFile } from "./data-formats.js";
|
|
4
|
+
|
|
5
|
+
test("JSON retains structured values and rejects malformed content", async () => {
|
|
6
|
+
const value = { name: "Málaga", enabled: true, count: 2, values: [null, "001"] };
|
|
7
|
+
assert.deepEqual(await decodeDataFile("json", encodeDataFile("json", value)), value);
|
|
8
|
+
await assert.rejects(decodeDataFile("json", new TextEncoder().encode('{"bad":')), SyntaxError);
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
test("CSV retains quoted commas, quotes, newlines, empty cells and leading zeroes", async () => {
|
|
12
|
+
const rows = [["id", "description"], ["001", 'comma, quote " and\nnewline'], ["002", ""]];
|
|
13
|
+
assert.deepEqual(await decodeDataFile("csv", encodeDataFile("csv", rows)), rows);
|
|
14
|
+
await assert.rejects(decodeDataFile("csv", new TextEncoder().encode('"unterminated')), /Quote Not Closed/);
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
test("Parquet creates an actual file and reads explicit typed nullable columns", async () => {
|
|
18
|
+
const encoded = encodeDataFile("parquet", [
|
|
19
|
+
{ name: "name", type: "STRING", data: ["Málaga", "Sydney"] },
|
|
20
|
+
{ name: "count", type: "INT32", data: [3, null] },
|
|
21
|
+
{ name: "active", type: "BOOLEAN", data: [true, false] }
|
|
22
|
+
]);
|
|
23
|
+
assert.equal(new TextDecoder().decode(encoded.slice(0, 4)), "PAR1");
|
|
24
|
+
const padded = new Uint8Array(encoded.length + 6);
|
|
25
|
+
padded.set(encoded, 3);
|
|
26
|
+
assert.deepEqual(await decodeDataFile("parquet", padded.subarray(3, -3)), [
|
|
27
|
+
{ name: "Málaga", count: 3, active: true }, { name: "Sydney", count: null, active: false }
|
|
28
|
+
]);
|
|
29
|
+
await assert.rejects(decodeDataFile("parquet", encoded.slice(0, 12)));
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
test("native composition rejects invalid UTF-8, excess bytes and unknown formats", async () => {
|
|
33
|
+
await assert.rejects(decodeDataFile("csv", new Uint8Array([255])), TypeError);
|
|
34
|
+
await assert.rejects(decodeDataFile("json", new Uint8Array(9), { maxBytes: 8 }), RangeError);
|
|
35
|
+
await assert.rejects(decodeDataFile("xml", new Uint8Array()), TypeError);
|
|
36
|
+
assert.throws(() => encodeDataFile("xml", []), TypeError);
|
|
37
|
+
});
|