@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.
Files changed (399) hide show
  1. package/README.md +192 -0
  2. package/docs/ai-upstream-notices.md +51 -0
  3. package/docs/ai.md +191 -0
  4. package/docs/airtable.md +130 -0
  5. package/docs/algolia.md +190 -0
  6. package/docs/amazon-redshift.md +229 -0
  7. package/docs/amplitude.md +210 -0
  8. package/docs/apify.md +162 -0
  9. package/docs/apollo-io.md +200 -0
  10. package/docs/asana.md +126 -0
  11. package/docs/ashby.md +188 -0
  12. package/docs/atlassian.md +224 -0
  13. package/docs/attention.md +162 -0
  14. package/docs/aws-athena.md +150 -0
  15. package/docs/aws-credentials.md +75 -0
  16. package/docs/aws-s3.md +193 -0
  17. package/docs/bigquery.md +146 -0
  18. package/docs/brevo.md +122 -0
  19. package/docs/calendly.md +158 -0
  20. package/docs/canva.md +191 -0
  21. package/docs/chargebee.md +192 -0
  22. package/docs/clay.md +194 -0
  23. package/docs/clickhouse.md +242 -0
  24. package/docs/confidence-exp.md +74 -0
  25. package/docs/confidence-flags.md +75 -0
  26. package/docs/confidence-oauth.md +137 -0
  27. package/docs/contentful.md +123 -0
  28. package/docs/databricks.md +180 -0
  29. package/docs/dbt-semantic-layer.md +175 -0
  30. package/docs/elevenlabs.md +102 -0
  31. package/docs/figma.md +132 -0
  32. package/docs/firebase-cloud-messaging.md +262 -0
  33. package/docs/firecrawl.md +137 -0
  34. package/docs/fireflies.md +95 -0
  35. package/docs/fireworks-ai.md +53 -0
  36. package/docs/gatewayapi.md +113 -0
  37. package/docs/gemini-enterprise.md +224 -0
  38. package/docs/github-api.md +133 -0
  39. package/docs/gitlab-api.md +138 -0
  40. package/docs/gmail.md +133 -0
  41. package/docs/gong.md +205 -0
  42. package/docs/google-ads.md +156 -0
  43. package/docs/google-analytics.md +202 -0
  44. package/docs/google-docs.md +105 -0
  45. package/docs/google-drive.md +108 -0
  46. package/docs/google-maps-platform.md +208 -0
  47. package/docs/google-oauth.md +123 -0
  48. package/docs/google-search-console.md +124 -0
  49. package/docs/google-sheets.md +94 -0
  50. package/docs/google-slides.md +95 -0
  51. package/docs/granola.md +178 -0
  52. package/docs/hex.md +161 -0
  53. package/docs/heygen.md +124 -0
  54. package/docs/hubspot.md +142 -0
  55. package/docs/incident-io.md +118 -0
  56. package/docs/inngest.md +178 -0
  57. package/docs/klipy.md +149 -0
  58. package/docs/lexware.md +144 -0
  59. package/docs/lightspeed.md +193 -0
  60. package/docs/linear.md +137 -0
  61. package/docs/linkedin.md +196 -0
  62. package/docs/logo-dev.md +152 -0
  63. package/docs/mailgun.md +153 -0
  64. package/docs/mapbox.md +174 -0
  65. package/docs/microsoft-excel.md +97 -0
  66. package/docs/microsoft-fabric.md +249 -0
  67. package/docs/microsoft-oauth.md +143 -0
  68. package/docs/microsoft-onedrive.md +76 -0
  69. package/docs/microsoft-onenote.md +75 -0
  70. package/docs/microsoft-outlook.md +90 -0
  71. package/docs/microsoft-powerpoint.md +119 -0
  72. package/docs/microsoft-sharepoint.md +75 -0
  73. package/docs/microsoft-teams.md +72 -0
  74. package/docs/microsoft-word.md +119 -0
  75. package/docs/miro.md +117 -0
  76. package/docs/n8n.md +169 -0
  77. package/docs/notion.md +137 -0
  78. package/docs/oura.md +161 -0
  79. package/docs/paddle.md +168 -0
  80. package/docs/perplexity.md +85 -0
  81. package/docs/pipedrive.md +120 -0
  82. package/docs/polar.md +63 -0
  83. package/docs/posthog.md +227 -0
  84. package/docs/prestashop.md +151 -0
  85. package/docs/replicate.md +60 -0
  86. package/docs/resend.md +153 -0
  87. package/docs/salesforce.md +234 -0
  88. package/docs/sanity.md +122 -0
  89. package/docs/semrush.md +276 -0
  90. package/docs/sentry.md +112 -0
  91. package/docs/sevdesk.md +107 -0
  92. package/docs/shopify.md +206 -0
  93. package/docs/slack.md +257 -0
  94. package/docs/snowflake.md +271 -0
  95. package/docs/storyblok.md +130 -0
  96. package/docs/stripe.md +77 -0
  97. package/docs/supabase.md +51 -0
  98. package/docs/tally.md +105 -0
  99. package/docs/telegram.md +165 -0
  100. package/docs/tiktok.md +201 -0
  101. package/docs/twilio.md +284 -0
  102. package/docs/twitch.md +428 -0
  103. package/docs/wave.md +440 -0
  104. package/docs/wix.md +1249 -0
  105. package/docs/wiz.md +177 -0
  106. package/docs/woocommerce.md +400 -0
  107. package/docs/wordpress-com.md +358 -0
  108. package/docs/wordpress-self-hosted.md +252 -0
  109. package/docs/workday.md +292 -0
  110. package/docs/x-twitter.md +188 -0
  111. package/docs/xero.md +429 -0
  112. package/docs/zoho-books.md +214 -0
  113. package/docs/zoho-crm.md +192 -0
  114. package/package.json +153 -0
  115. package/patterns/ai-connections/PATTERN.md +84 -0
  116. package/patterns/ai-connections/example/ai-model.js +11 -0
  117. package/patterns/ai-connections/example/perplexity-answer.js +29 -0
  118. package/patterns/api-key-connection/PATTERN.md +368 -0
  119. package/patterns/api-key-connection/example/connections.js +18 -0
  120. package/patterns/api-key-connection/example/integrations.json +19 -0
  121. package/patterns/assistant-mcp/PATTERN.md +110 -0
  122. package/patterns/assistant-mcp/example/integrations.json +13 -0
  123. package/patterns/assistant-mcp-oauth/PATTERN.md +235 -0
  124. package/patterns/assistant-mcp-oauth/example/integrations.json +102 -0
  125. package/patterns/aws-storage-queries/PATTERN.md +169 -0
  126. package/patterns/aws-storage-queries/example/formats/data-formats.js +35 -0
  127. package/patterns/aws-storage-queries/example/formats/package-lock.json +49 -0
  128. package/patterns/aws-storage-queries/example/formats/package.json +12 -0
  129. package/patterns/aws-storage-queries/example/formats/verify-formats.mjs +37 -0
  130. package/patterns/aws-storage-queries/example/integrations.json +38 -0
  131. package/patterns/aws-storage-queries/example/s3-transfer.js +34 -0
  132. package/patterns/event-delivery/PATTERN.md +151 -0
  133. package/patterns/event-delivery/example/integrations.json +17 -0
  134. package/patterns/firebase-messaging/PATTERN.md +156 -0
  135. package/patterns/firebase-messaging/example/server/notifications.js +23 -0
  136. package/patterns/google-ads-search/PATTERN.md +92 -0
  137. package/patterns/google-ads-search/example/ads-setup.js +25 -0
  138. package/patterns/oauth-connection/PATTERN.md +724 -0
  139. package/patterns/oauth-connection/example/integrations.json +20 -0
  140. package/patterns/paddle-catalogue/PATTERN.md +78 -0
  141. package/patterns/paddle-catalogue/example/create-products.js +38 -0
  142. package/patterns/public-image/PATTERN.md +84 -0
  143. package/patterns/public-image/example/integrations.json +13 -0
  144. package/patterns/public-image/example/logo-url.js +16 -0
  145. package/patterns/redshift-queries/PATTERN.md +150 -0
  146. package/patterns/redshift-queries/example/integrations.json +33 -0
  147. package/patterns/source-scanning/PATTERN.md +83 -0
  148. package/patterns/source-scanning/example/source-scanner.js +13 -0
  149. package/src/client/firebase-cloud-messaging.js +10 -0
  150. package/src/client/google-analytics.js +72 -0
  151. package/src/client/google-maps-platform.js +39 -0
  152. package/src/client/logo-dev.js +36 -0
  153. package/src/server/ai.js +46 -0
  154. package/src/server/airtable.js +67 -0
  155. package/src/server/algolia.js +63 -0
  156. package/src/server/amazon-redshift.js +96 -0
  157. package/src/server/amplitude.js +31 -0
  158. package/src/server/apify.js +68 -0
  159. package/src/server/apollo-io.js +85 -0
  160. package/src/server/asana.js +64 -0
  161. package/src/server/ashby.js +61 -0
  162. package/src/server/atlassian.js +32 -0
  163. package/src/server/attention.js +93 -0
  164. package/src/server/aws-athena.js +82 -0
  165. package/src/server/aws-s3.js +49 -0
  166. package/src/server/awsTransport.js +75 -0
  167. package/src/server/bigquery.js +97 -0
  168. package/src/server/brevo.js +97 -0
  169. package/src/server/calendly.js +77 -0
  170. package/src/server/canva.js +13 -0
  171. package/src/server/chargebee.js +88 -0
  172. package/src/server/clay.js +78 -0
  173. package/src/server/clickhouse.js +66 -0
  174. package/src/server/confidence.js +29 -0
  175. package/src/server/contentful.js +40 -0
  176. package/src/server/databricks.js +55 -0
  177. package/src/server/dbt-semantic-layer.js +95 -0
  178. package/src/server/elevenlabs.js +81 -0
  179. package/src/server/figma.js +24 -0
  180. package/src/server/firebase-cloud-messaging.js +111 -0
  181. package/src/server/firecrawl.js +70 -0
  182. package/src/server/fireflies.js +31 -0
  183. package/src/server/fireworks-ai.js +16 -0
  184. package/src/server/gatewayapi.js +48 -0
  185. package/src/server/gemini-enterprise.js +47 -0
  186. package/src/server/github-api.js +90 -0
  187. package/src/server/gitlab-api.js +67 -0
  188. package/src/server/gmail.js +60 -0
  189. package/src/server/gong.js +52 -0
  190. package/src/server/google-ads-search.js +134 -0
  191. package/src/server/google-ads.js +80 -0
  192. package/src/server/google-docs.js +36 -0
  193. package/src/server/google-drive.js +71 -0
  194. package/src/server/google-maps-platform.js +90 -0
  195. package/src/server/google-search-console.js +31 -0
  196. package/src/server/google-sheets.js +60 -0
  197. package/src/server/google-slides.js +36 -0
  198. package/src/server/google.js +61 -0
  199. package/src/server/granola.js +115 -0
  200. package/src/server/graphqlOperation.js +15 -0
  201. package/src/server/hex.js +29 -0
  202. package/src/server/heygen.js +54 -0
  203. package/src/server/hubspot.js +85 -0
  204. package/src/server/incident-io.js +68 -0
  205. package/src/server/inngest.js +86 -0
  206. package/src/server/jsonOperation.js +34 -0
  207. package/src/server/klipy.js +34 -0
  208. package/src/server/lexware.js +59 -0
  209. package/src/server/lightspeed.js +82 -0
  210. package/src/server/linear.js +52 -0
  211. package/src/server/linkedin.js +74 -0
  212. package/src/server/mailgun.js +76 -0
  213. package/src/server/mapbox.js +46 -0
  214. package/src/server/mcpRegistration.js +41 -0
  215. package/src/server/mcpTransport.js +60 -0
  216. package/src/server/microsoft-excel.js +67 -0
  217. package/src/server/microsoft-fabric.js +81 -0
  218. package/src/server/microsoft-onedrive.js +58 -0
  219. package/src/server/microsoft-onenote.js +52 -0
  220. package/src/server/microsoft-outlook.js +58 -0
  221. package/src/server/microsoft-powerpoint.js +5 -0
  222. package/src/server/microsoft-sharepoint.js +46 -0
  223. package/src/server/microsoft-teams.js +29 -0
  224. package/src/server/microsoft-word.js +5 -0
  225. package/src/server/microsoft.js +88 -0
  226. package/src/server/miro.js +29 -0
  227. package/src/server/n8n.js +78 -0
  228. package/src/server/notion.js +76 -0
  229. package/src/server/oura.js +48 -0
  230. package/src/server/paddle.js +83 -0
  231. package/src/server/perplexity.js +15 -0
  232. package/src/server/pipedrive.js +95 -0
  233. package/src/server/polar.js +20 -0
  234. package/src/server/posthog.js +44 -0
  235. package/src/server/prestashop.js +42 -0
  236. package/src/server/replicate.js +42 -0
  237. package/src/server/resend.js +93 -0
  238. package/src/server/salesforce.js +84 -0
  239. package/src/server/sanity.js +31 -0
  240. package/src/server/semrush.js +359 -0
  241. package/src/server/sentry.js +30 -0
  242. package/src/server/sevdesk.js +20 -0
  243. package/src/server/shopify.js +99 -0
  244. package/src/server/slack.js +143 -0
  245. package/src/server/snowflake.js +139 -0
  246. package/src/server/storyblok.js +49 -0
  247. package/src/server/stripe.js +13 -0
  248. package/src/server/supabase.js +13 -0
  249. package/src/server/tally.js +78 -0
  250. package/src/server/telegram.js +55 -0
  251. package/src/server/tiktok.js +86 -0
  252. package/src/server/twilio.js +90 -0
  253. package/src/server/twitch.js +409 -0
  254. package/src/server/wave.js +520 -0
  255. package/src/server/wix.js +1048 -0
  256. package/src/server/wiz.js +117 -0
  257. package/src/server/woocommerce.js +412 -0
  258. package/src/server/wordpress-com.js +236 -0
  259. package/src/server/wordpress-self-hosted.js +134 -0
  260. package/src/server/workday.js +136 -0
  261. package/src/server/x-twitter.js +110 -0
  262. package/src/server/xero.js +397 -0
  263. package/src/server/zoho-books.js +90 -0
  264. package/src/server/zoho-crm.js +89 -0
  265. package/src/server/zohoOAuth.js +21 -0
  266. package/src/shared/ai-models.json +8049 -0
  267. package/src/shared/ai.js +63 -0
  268. package/src/shared/algolia.js +29 -0
  269. package/src/shared/amazon-redshift.js +51 -0
  270. package/src/shared/amplitude.js +28 -0
  271. package/src/shared/atlassian.js +43 -0
  272. package/src/shared/aws.js +72 -0
  273. package/src/shared/canva.js +66 -0
  274. package/src/shared/chargebee.js +26 -0
  275. package/src/shared/clickhouse.js +38 -0
  276. package/src/shared/confidence.js +28 -0
  277. package/src/shared/databricks.js +33 -0
  278. package/src/shared/dbt-semantic-layer.js +32 -0
  279. package/src/shared/definitions.js +140 -0
  280. package/src/shared/figma.js +21 -0
  281. package/src/shared/firebase-cloud-messaging.js +45 -0
  282. package/src/shared/gemini-enterprise.js +33 -0
  283. package/src/shared/gong.js +33 -0
  284. package/src/shared/google-ads-search.js +31 -0
  285. package/src/shared/google-ads.js +28 -0
  286. package/src/shared/google-maps-platform.js +28 -0
  287. package/src/shared/google.js +133 -0
  288. package/src/shared/granola.js +25 -0
  289. package/src/shared/hex.js +28 -0
  290. package/src/shared/inngest.js +35 -0
  291. package/src/shared/lightspeed.js +75 -0
  292. package/src/shared/linkedin.js +27 -0
  293. package/src/shared/logo-dev.js +21 -0
  294. package/src/shared/mapbox.js +38 -0
  295. package/src/shared/mcp.js +92 -0
  296. package/src/shared/microsoft-fabric.js +47 -0
  297. package/src/shared/microsoft.js +231 -0
  298. package/src/shared/miro.js +27 -0
  299. package/src/shared/oura.js +23 -0
  300. package/src/shared/posthog.js +33 -0
  301. package/src/shared/prestashop.js +23 -0
  302. package/src/shared/salesforce.js +36 -0
  303. package/src/shared/semrush.js +24 -0
  304. package/src/shared/shopify.js +51 -0
  305. package/src/shared/siteUrl.js +12 -0
  306. package/src/shared/slack.js +88 -0
  307. package/src/shared/snowflake.js +55 -0
  308. package/src/shared/tiktok.js +22 -0
  309. package/src/shared/tokens.js +747 -0
  310. package/src/shared/twilio.js +41 -0
  311. package/src/shared/twitch.js +49 -0
  312. package/src/shared/wave.js +52 -0
  313. package/src/shared/wix.js +40 -0
  314. package/src/shared/wiz.js +41 -0
  315. package/src/shared/wordpress-com.js +30 -0
  316. package/src/shared/wordpress.js +69 -0
  317. package/src/shared/workday.js +50 -0
  318. package/src/shared/x-twitter.js +19 -0
  319. package/src/shared/xero.js +46 -0
  320. package/src/shared/zoho-books.js +39 -0
  321. package/src/shared/zoho-crm.js +43 -0
  322. package/src/shared/zoho-regions.js +12 -0
  323. package/test/ai.test.js +136 -0
  324. package/test/airtable.test.js +125 -0
  325. package/test/algolia.test.js +207 -0
  326. package/test/amazon-redshift.test.js +272 -0
  327. package/test/amplitude.test.js +239 -0
  328. package/test/apify.test.js +93 -0
  329. package/test/apollo-io.test.js +125 -0
  330. package/test/asana.test.js +99 -0
  331. package/test/ashby.test.js +97 -0
  332. package/test/atlassian.test.js +249 -0
  333. package/test/attention.test.js +79 -0
  334. package/test/aws.test.js +405 -0
  335. package/test/brevo.test.js +71 -0
  336. package/test/calendly.test.js +136 -0
  337. package/test/canva.test.js +258 -0
  338. package/test/chargebee.test.js +195 -0
  339. package/test/clickhouse.test.js +278 -0
  340. package/test/confidence.test.js +205 -0
  341. package/test/databricks.test.js +253 -0
  342. package/test/dbt-semantic-layer.test.js +221 -0
  343. package/test/designMcp.test.js +336 -0
  344. package/test/elevenlabs.test.js +52 -0
  345. package/test/firebase-cloud-messaging.test.js +242 -0
  346. package/test/firecrawl.test.js +66 -0
  347. package/test/gemini-enterprise.test.js +218 -0
  348. package/test/github-api.test.js +167 -0
  349. package/test/gitlab-api.test.js +160 -0
  350. package/test/gong.test.js +192 -0
  351. package/test/google-ads.test.js +350 -0
  352. package/test/google-maps-platform.test.js +191 -0
  353. package/test/google.test.js +710 -0
  354. package/test/granola.test.js +240 -0
  355. package/test/hex.test.js +253 -0
  356. package/test/heygen.test.js +121 -0
  357. package/test/hubspot.test.js +103 -0
  358. package/test/inngest.test.js +219 -0
  359. package/test/lightspeed.test.js +250 -0
  360. package/test/linear.test.js +146 -0
  361. package/test/linkedin.test.js +243 -0
  362. package/test/logo-dev.test.js +79 -0
  363. package/test/mailgun.test.js +107 -0
  364. package/test/mapbox.test.js +181 -0
  365. package/test/mcp.test.js +227 -0
  366. package/test/microsoft-fabric.test.js +258 -0
  367. package/test/microsoft.test.js +554 -0
  368. package/test/n8nOAuth.test.js +188 -0
  369. package/test/notionOAuth.test.js +183 -0
  370. package/test/oura.test.js +211 -0
  371. package/test/paddleCatalogue.test.js +51 -0
  372. package/test/paddlePermissions.test.js +101 -0
  373. package/test/perplexityComposition.test.js +39 -0
  374. package/test/pipedriveOAuth.test.js +140 -0
  375. package/test/posthog.test.js +200 -0
  376. package/test/prestashop.test.js +207 -0
  377. package/test/resend.test.js +163 -0
  378. package/test/salesforce.test.js +276 -0
  379. package/test/semrush.test.js +479 -0
  380. package/test/sentry.test.js +35 -0
  381. package/test/shopify.test.js +247 -0
  382. package/test/slack.test.js +320 -0
  383. package/test/snowflake.test.js +391 -0
  384. package/test/tally.test.js +75 -0
  385. package/test/telegram.test.js +58 -0
  386. package/test/tiktok.test.js +243 -0
  387. package/test/tokens.test.js +1079 -0
  388. package/test/twilio.test.js +221 -0
  389. package/test/twitch.test.js +573 -0
  390. package/test/wave.test.js +678 -0
  391. package/test/wix.test.js +1099 -0
  392. package/test/wiz.test.js +185 -0
  393. package/test/wordpress-com.test.js +469 -0
  394. package/test/wordpress.test.js +660 -0
  395. package/test/workday.test.js +314 -0
  396. package/test/x-twitter.test.js +256 -0
  397. package/test/xero.test.js +700 -0
  398. package/test/zoho-books.test.js +253 -0
  399. 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
+ });