@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,76 @@
1
+ import { createSchema } from "json-rest-schema";
2
+ import { validateSchemaPayload } from "@jskit-ai/kernel/shared/validators";
3
+ import { mcpOperations, exchangeMcp } from "./mcpTransport.js";
4
+ import { mcpRegistrationFields, registerMcpClient } from "./mcpRegistration.js";
5
+ import { notionDefinition } from "../shared/tokens.js";
6
+ import { jsonOperation, validatedOperation } from "./jsonOperation.js";
7
+
8
+ const identifier = { type: "string", required: true, pattern: "^(?:[a-fA-F0-9]{32}|[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12})$" };
9
+ const document = { type: "object", additionalProperties: true,
10
+ validator: value => Buffer.byteLength(JSON.stringify(value)) <= 65536 || "Keep each document below 64 KiB." };
11
+ const pagination = { page_size: { type: "integer", min: 1, max: 100, defaultTo: 100 },
12
+ start_cursor: { type: "string", minLength: 1, maxLength: 4096 } };
13
+ const listResult = result => result?.object === "list" && Array.isArray(result.results) && typeof result.has_more === "boolean";
14
+ const objectResult = object => result => result?.object === object && typeof result.id === "string" && result.id.length > 0;
15
+ const children = { type: "array", required: true, minLength: 1, maxLength: 100,
16
+ items: { ...document, required: true }, validator: value => value.length >= 1 && value.length <= 100 && Buffer.byteLength(JSON.stringify(value)) <= 262144 || "Keep blocks below 256 KiB." };
17
+ // Notion owns its property/block grammar. Bound documents without inventing a second content schema.
18
+ function readObject(collection, object) {
19
+ return validatedOperation({ id: identifier }, ({ id }) => ({ method: "GET", url: `https://api.notion.com/v1/${collection}/${id}` }), objectResult(object));
20
+ }
21
+
22
+ const mcpMetadata = Object.freeze({ issuer: "https://mcp.notion.com",
23
+ authorization_endpoint: "https://mcp.notion.com/authorize", token_endpoint: "https://mcp.notion.com/token",
24
+ registration_endpoint: "https://mcp.notion.com/register" });
25
+ const mcpRuntime = Object.freeze({ oauth: mcpMetadata, oauthPkce: true,
26
+ oauthBasicEncoding: undefined, tokenRequestEncoding: undefined, authorizationParameters: {}, oauthHeaders: undefined,
27
+ apiOrigins: ["https://mcp.notion.com"], checkOperation: "tools.list", exchange: exchangeMcp,
28
+ operations: mcpOperations(() => "https://mcp.notion.com/mcp") });
29
+ const notionProvider = Object.freeze({
30
+ ...notionDefinition,
31
+ runtimeForSettings: (settings) => settings.connectionType === "mcp" ? mcpRuntime : {},
32
+ oauth: {
33
+ issuer: "https://api.notion.com",
34
+ authorization_endpoint: "https://api.notion.com/v1/oauth/authorize",
35
+ token_endpoint: "https://api.notion.com/v1/oauth/token"
36
+ },
37
+ oauthPkce: false,
38
+ oauthBasicEncoding: "raw",
39
+ tokenRequestEncoding: "json",
40
+ authorizationParameters: { owner: "user" },
41
+ oauthHeaders: () => ({ "Notion-Version": "2026-03-11" }),
42
+ apiOrigins: ["https://api.notion.com"],
43
+ apiKey: { headers: (key) => ({ Authorization: `Bearer ${key}`, "Notion-Version": "2026-03-11" }) },
44
+ checkOperation: "content.search",
45
+ operations: {
46
+ "pages.get": readObject("pages", "page"),
47
+ "databases.get": readObject("databases", "database"),
48
+ "dataSources.get": readObject("data_sources", "data_source"),
49
+ "blocks.list": validatedOperation({ id: identifier, ...pagination }, ({ id, ...query }) => ({ method: "GET",
50
+ url: `https://api.notion.com/v1/blocks/${id}/children?${new URLSearchParams(query)}` }), listResult),
51
+ "dataSources.query": validatedOperation({ id: identifier, ...pagination, filter: document,
52
+ sorts: { type: "array", validator: value => value.length <= 20 || "Use at most 20 sorts.", items: document } }, ({ id, ...body }) => ({ method: "POST",
53
+ url: `https://api.notion.com/v1/data_sources/${id}/query`, body }), listResult),
54
+ "pages.create": validatedOperation({ parentId: identifier, parentType: { type: "string", required: true, enum: ["page_id", "data_source_id"] },
55
+ properties: { ...document, required: true }, children: { ...children, required: false } },
56
+ ({ parentId, parentType, ...body }) => ({ method: "POST", url: "https://api.notion.com/v1/pages",
57
+ body: { parent: { type: parentType, [parentType]: parentId }, ...body } }), objectResult("page")),
58
+ "pages.update": validatedOperation({ id: identifier, properties: { ...document, required: true } },
59
+ ({ id, ...body }) => ({ method: "PATCH", url: `https://api.notion.com/v1/pages/${id}`, body }), objectResult("page")),
60
+ "blocks.append": validatedOperation({ id: identifier, children }, ({ id, ...body }) => ({ method: "PATCH",
61
+ url: `https://api.notion.com/v1/blocks/${id}/children`, body }), listResult),
62
+ "content.search": jsonOperation("https://api.notion.com/v1/search", {
63
+ query: { type: "string", maxLength: 4096 },
64
+ page_size: { type: "integer", min: 1, max: 100, defaultTo: 100 },
65
+ start_cursor: { type: "string", minLength: 1, maxLength: 4096 }
66
+ }, (result) => result?.object === "list" && Array.isArray(result.results) && typeof result.has_more === "boolean", "POST"),
67
+ "identity.read": jsonOperation("https://api.notion.com/v1/users/me", {},
68
+ (result) => result?.object === "user" && typeof result.id === "string" && ["bot", "person"].includes(result.type))
69
+ }
70
+ });
71
+ const registrationSchema = createSchema(mcpRegistrationFields);
72
+ async function registerNotionMcpClient(input, options) {
73
+ const values = validateSchemaPayload({ schema: registrationSchema, mode: "replace" }, input, { statusCode: 422 });
74
+ return registerMcpClient("Notion MCP", mcpMetadata, { ...values, scopes: ["default"] }, options);
75
+ }
76
+ export { notionProvider, registerNotionMcpClient };
@@ -0,0 +1,48 @@
1
+ import { ConnectorError } from "@jskit-ai/connectors-core/server";
2
+ import { ouraDefinition } from "../shared/oura.js";
3
+ import { jsonOperation } from "./jsonOperation.js";
4
+
5
+ const date = {
6
+ type: "string",
7
+ validator: (value) => (/^\d{4}-\d{2}-\d{2}$/u.test(value) &&
8
+ Number.isFinite(Date.parse(value)) && new Date(value).toISOString().slice(0, 10) === value) || "Enter a valid date as YYYY-MM-DD."
9
+ };
10
+ const datetime = { type: "string", validator: value =>
11
+ /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{1,3})?(?:Z|[+-]\d{2}:\d{2})$/.test(value) && Number.isFinite(Date.parse(value)) && date.validator(value.slice(0, 10)) === true || "Enter an ISO timestamp with timezone." };
12
+ function collection(endpoint, scope = "daily", timed = false) {
13
+ const start = timed ? "start_datetime" : "start_date", end = timed ? "end_datetime" : "end_date";
14
+ const operation = jsonOperation(`https://api.ouraring.com/v2/usercollection/${endpoint}`, {
15
+ [start]: timed ? datetime : date, [end]: timed ? datetime : date,
16
+ next_token: { type: "string", minLength: 1, maxLength: 4096 }
17
+ }, result => Array.isArray(result?.data) && (result.next_token == null || typeof result.next_token === "string"));
18
+ return { ...operation, scopes: [scope], request(input, settings) {
19
+ const request = operation.request(input, settings);
20
+ const query = new URL(request.url).searchParams;
21
+ if (query.has(start) && query.has(end) && Date.parse(query.get(start)) > Date.parse(query.get(end)))
22
+ throw new ConnectorError("connector_input_invalid", "Start must be before or equal to end.", { statusCode: 422 });
23
+ return request;
24
+ } };
25
+ }
26
+ const ouraProvider = Object.freeze({
27
+ ...ouraDefinition,
28
+ oauth: {
29
+ issuer: "https://cloud.ouraring.com",
30
+ authorization_endpoint: "https://cloud.ouraring.com/oauth/authorize",
31
+ token_endpoint: "https://api.ouraring.com/oauth/token"
32
+ },
33
+ scopesInAuthorizationResponse: true,
34
+ apiOrigins: ["https://api.ouraring.com"], checkOperation: "dailySleep.list",
35
+ operations: {
36
+ "dailySleep.list": collection("daily_sleep"),
37
+ "sleep.list": collection("sleep"),
38
+ "dailyReadiness.list": collection("daily_readiness"),
39
+ "dailyActivity.list": collection("daily_activity"),
40
+ "heartRate.list": collection("heartrate", "heartrate", true),
41
+ "personalInfo.read": {
42
+ ...jsonOperation("https://api.ouraring.com/v2/usercollection/personal_info", {},
43
+ (result) => typeof result?.id === "string" && result.id.length > 0),
44
+ scopes: ["personal", "email"]
45
+ }
46
+ }
47
+ });
48
+ export { ouraProvider };
@@ -0,0 +1,83 @@
1
+ import { createSchema } from "json-rest-schema";
2
+ import { validateSchemaPayload } from "@jskit-ai/kernel/shared/validators";
3
+ import { ConnectorError } from "@jskit-ai/connectors-core/server";
4
+ import { paddleDefinition } from "../shared/tokens.js";
5
+ import { jsonOperation } from "./jsonOperation.js";
6
+
7
+ const origins = { sandbox: "https://sandbox-api.paddle.com", live: "https://api.paddle.com" };
8
+ const webhookUpdateSchema = createSchema({
9
+ notification_setting_id: { type: "string", required: true,
10
+ validator: (value) => /^ntfset_[a-z0-9]{26}$/.test(value) || "Enter a Paddle notification setting ID." },
11
+ description: { type: "string", minLength: 1, maxLength: 500 },
12
+ destination: { type: "string", minLength: 1, maxLength: 2048 },
13
+ active: { type: "boolean" },
14
+ api_version: { type: "integer", min: 1 },
15
+ include_sensitive_fields: { type: "boolean" },
16
+ subscribed_events: { type: "array", items: { type: "string", minLength: 3, maxLength: 100,
17
+ validator: (value) => /^[a-z_]+\.[a-z_]+$/.test(value) || "Use a Paddle event type name." } },
18
+ traffic_source: { type: "string", enum: ["platform", "simulation", "all"] }
19
+ });
20
+ const paddleProvider = Object.freeze({
21
+ ...paddleDefinition, apiOrigins: Object.values(origins),
22
+ apiKey: { headers: (key) => ({ Authorization: `Bearer ${key}`, "Paddle-Version": "1" }) },
23
+ checkOperation: "products.list",
24
+ async exchange(address, options, { request }) {
25
+ const result = await request(address, options);
26
+ if (new URL(address).pathname.startsWith("/notification-settings/") && result?.data) {
27
+ // Editing a destination must not expose its signing secret to assistant tools.
28
+ const { endpoint_secret_key, ...data } = result.data;
29
+ return { ...result, data };
30
+ }
31
+ return result;
32
+ },
33
+ operations: {
34
+ "checkoutDomains.get": {
35
+ scopes: [], assistantAction: "goLive.check",
36
+ request(input, settings) {
37
+ const { domain_id } = validateSchemaPayload({ schema: createSchema({
38
+ domain_id: { type: "string", required: true,
39
+ validator: (value) => /^chedom_[a-z0-9]{26}$/.test(value) || "Enter a Paddle checkout domain ID." }
40
+ }), mode: "replace" }, input, { statusCode: 422 });
41
+ return { method: "GET", url: `${origins[settings.environment]}/checkout-domains/${domain_id}` };
42
+ },
43
+ validateResult: (result) => /^chedom_[a-z0-9]{26}$/.test(result?.data?.id || "") &&
44
+ typeof result.data.domain === "string" && result.data.domain.length > 0 &&
45
+ ["pending_review", "approved", "rejected", "in_review", "action_required"].includes(result.data.status)
46
+ },
47
+ "webhooks.update": {
48
+ scopes: [],
49
+ request(input, settings) {
50
+ const { notification_setting_id, ...body } = validateSchemaPayload(
51
+ { schema: webhookUpdateSchema, mode: "replace" }, input, { statusCode: 422 });
52
+ if (!Object.keys(body).length) throw new ConnectorError("connector_input_invalid", "Choose at least one notification setting to change.", { statusCode: 422 });
53
+ return { method: "PATCH", url: `${origins[settings.environment]}/notification-settings/${notification_setting_id}`, body };
54
+ },
55
+ validateResult: (result) => /^ntfset_[a-z0-9]{26}$/.test(result?.data?.id || "") && typeof result.data.active === "boolean"
56
+ },
57
+ "products.create": jsonOperation((settings) => `${origins[settings.environment]}/products`, {
58
+ name: { type: "string", required: true, minLength: 1, maxLength: 200 },
59
+ description: { type: "string", maxLength: 2048 },
60
+ tax_category: { type: "string", required: true, enum: ["digital-goods", "ebooks", "implementation-services", "professional-services", "saas", "software-programming-services", "standard", "training-services", "website-hosting"] }
61
+ }, (result) => /^pro_[a-z0-9]{26}$/.test(result?.data?.id || ""), "POST"),
62
+ "prices.create": jsonOperation((settings) => `${origins[settings.environment]}/prices`, {
63
+ product_id: { type: "string", required: true, validator: (value) => /^pro_[a-z0-9]{26}$/.test(value) || "Enter a Paddle product ID." },
64
+ description: { type: "string", required: true, minLength: 2, maxLength: 500 },
65
+ unit_price: { type: "object", required: true, schema: createSchema({
66
+ amount: { type: "string", required: true, validator: (value) => /^\d+$/.test(value) || "Enter an integer amount in the currency's smallest unit." },
67
+ currency_code: { type: "string", required: true, validator: (value) => /^[A-Z]{3}$/.test(value) || "Enter a three-letter currency code supported by Paddle." }
68
+ }) },
69
+ billing_cycle: { type: "object", schema: createSchema({
70
+ interval: { type: "string", required: true, enum: ["day", "week", "month", "year"] },
71
+ frequency: { type: "integer", required: true, min: 1 }
72
+ }) }
73
+ }, (result) => /^pri_[a-z0-9]{26}$/.test(result?.data?.id || ""), "POST"),
74
+
75
+ "products.list": { assistantAction: "api.read", ...jsonOperation((settings) => `${origins[settings.environment]}/products`, {
76
+ per_page: { type: "integer", min: 1, max: 200, defaultTo: 50 },
77
+ after: { type: "string", maxLength: 200 },
78
+ status: { type: "string", enum: ["active", "archived"], defaultTo: "active" }
79
+ }, (result) => Array.isArray(result?.data) && Boolean(result.meta?.pagination)
80
+ && typeof result.meta.pagination.has_more === "boolean") }
81
+ }
82
+ });
83
+ export { paddleProvider };
@@ -0,0 +1,15 @@
1
+ import { perplexityDefinition } from "../shared/tokens.js";
2
+ import { jsonOperation } from "./jsonOperation.js";
3
+
4
+ const perplexityProvider = Object.freeze({
5
+ ...perplexityDefinition, apiOrigins: ["https://api.perplexity.ai"],
6
+ apiKey: { headers: (key) => ({ Authorization: `Bearer ${key}` }) },
7
+ checkOperation: "requests.list",
8
+ operations: {
9
+ "requests.list": jsonOperation("https://api.perplexity.ai/v1/async/sonar", {},
10
+ (result) => Array.isArray(result?.requests) && (result.next_token === undefined || result.next_token === null || typeof result.next_token === "string")),
11
+ "models.list": jsonOperation("https://api.perplexity.ai/v1/models", {},
12
+ (result) => result?.object === "list" && Array.isArray(result.data))
13
+ }
14
+ });
15
+ export { perplexityProvider };
@@ -0,0 +1,95 @@
1
+ import { createSchema } from "json-rest-schema";
2
+ import { validateSchemaPayload } from "@jskit-ai/kernel/shared/validators";
3
+ import { pipedriveDefinition } from "../shared/tokens.js";
4
+ import { jsonOperation } from "./jsonOperation.js";
5
+ import { ConnectorError } from "@jskit-ai/connectors-core/server";
6
+
7
+ function companyApiDomain(value) {
8
+ if (typeof value !== "string" || !/^https:\/\/[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.pipedrive\.com$/.test(value)) {
9
+ throw new ConnectorError("connector_response_invalid", "Pipedrive returned an invalid company API address.", { statusCode: 502 });
10
+ }
11
+ return value;
12
+ }
13
+
14
+ const numberId = { type: "integer", min: 1 };
15
+ const text = { type: "string", minLength: 1, maxLength: 1000 };
16
+ const contactValues = { type: "array", validator: values => values.length <= 20 || "Use at most 20 contact values.",
17
+ items: { type: "object", schema: createSchema({ value: { ...text, required: true }, primary: { type: "boolean" }, label: text }) } };
18
+ const recordFields = {
19
+ deals: { title: text, person_id: numberId, org_id: numberId, owner_id: numberId, stage_id: numberId,
20
+ value: { type: "number", min: 0 }, currency: { type: "string", pattern: "^[A-Z]{3}$" }, status: { type: "string", enum: ["open", "won", "lost"] } },
21
+ persons: { name: text, org_id: numberId, owner_id: numberId, emails: contactValues, phones: contactValues },
22
+ organizations: { name: text, owner_id: numberId },
23
+ activities: { subject: text, type: text, person_id: numberId, org_id: numberId, deal_id: numberId,
24
+ done: { type: "boolean" }, due_date: { type: "string", pattern: "^\\d{4}-\\d{2}-\\d{2}$" }, due_time: { type: "string", pattern: "^\\d{2}:\\d{2}$" } },
25
+ leads: { title: text, person_id: numberId, organization_id: numberId, owner_id: numberId }
26
+ };
27
+ function crmOperation(collection, action) {
28
+ const lead = collection === "leads", write = ["create", "update"].includes(action);
29
+ const id = lead ? { type: "string", pattern: "^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$" } : numberId;
30
+ const primary = ["deals", "leads"].includes(collection) ? "title" : collection === "activities" ? "subject" : "name";
31
+ const fields = write ? { ...recordFields[collection], ...(action === "create" ? { [primary]: { ...text, required: true } } : {}) } : action === "list"
32
+ ? { limit: { type: "integer", min: 1, max: 500, defaultTo: 100 }, ...(lead ? { start: { type: "integer", min: 0 } } : { cursor: { type: "string", minLength: 1, maxLength: 4096 } }) } : {};
33
+ const schema = createSchema({ ...fields, ...(["get", "update"].includes(action) ? { id: { ...id, required: true } } : {}) });
34
+ return { scopes: [], request(input, settings = {}, data) {
35
+ const { id, ...values } = validateSchemaPayload({ schema, mode: "replace" }, input, { statusCode: 422 });
36
+ if (action === "update" && !Object.keys(values).length || lead && action === "create" && !values.person_id && !values.organization_id)
37
+ throw new ConnectorError("connector_input_invalid", "Supply changed fields; a new lead also needs a person or organization.", { statusCode: 422 });
38
+ if (!data && !settings.companyDomain) throw new ConnectorError("connector_binding_missing", "Set the Pipedrive Company domain for API-token CRM operations.", { statusCode: 422 });
39
+ const origin = data ? companyApiDomain(data.apiDomain) : companyApiDomain(`https://${settings.companyDomain}.pipedrive.com`);
40
+ const url = new URL(`${origin}/api/${lead ? "v1" : "v2"}/${collection}${id === undefined ? "" : `/${id}`}`);
41
+ if (!write) for (const [name, value] of Object.entries(values)) url.searchParams.set(name, String(value));
42
+ return { method: action === "create" ? "POST" : action === "update" ? "PATCH" : "GET", url: url.href, ...(write ? { body: values } : {}) };
43
+ }, validateResult: result => result?.success === true && (action === "list" ? Array.isArray(result.data)
44
+ : lead ? typeof result.data?.id === "string" : Number.isInteger(result.data?.id)) };
45
+ }
46
+
47
+ const profile = jsonOperation("https://api.pipedrive.com/v1/users/me", {},
48
+ (result) => result?.success === true && Number.isInteger(result.data?.id));
49
+
50
+ const pipedriveProvider = Object.freeze({
51
+ ...pipedriveDefinition,
52
+ oauth: { issuer: "https://oauth.pipedrive.com", authorization_endpoint: "https://oauth.pipedrive.com/oauth/authorize",
53
+ token_endpoint: "https://oauth.pipedrive.com/oauth/token" },
54
+ oauthPkce: false,
55
+ oauthBasicEncoding: "raw",
56
+ dataFromTokenResponse(response, previous) {
57
+ const apiDomain = companyApiDomain(response.api_domain);
58
+ if (previous && apiDomain !== previous.apiDomain) {
59
+ throw new ConnectorError("connector_reconnect_required", "The Pipedrive company address changed. Connect this account again.", { statusCode: 401 });
60
+ }
61
+ return { apiDomain };
62
+ },
63
+ apiOrigins: (settings, data) => data ? [companyApiDomain(data.apiDomain)] : ["https://api.pipedrive.com", ...(settings.companyDomain ? [companyApiDomain(`https://${settings.companyDomain}.pipedrive.com`)] : [])],
64
+ apiKey: { headers: (key) => ({ "x-api-token": key }) },
65
+ checkOperation: "profile.read",
66
+ operations: {
67
+ "deals.list": crmOperation("deals", "list"),
68
+ "deals.get": crmOperation("deals", "get"),
69
+ "deals.create": crmOperation("deals", "create"),
70
+ "deals.update": crmOperation("deals", "update"),
71
+ "persons.list": crmOperation("persons", "list"),
72
+ "persons.get": crmOperation("persons", "get"),
73
+ "persons.create": crmOperation("persons", "create"),
74
+ "persons.update": crmOperation("persons", "update"),
75
+ "organizations.list": crmOperation("organizations", "list"),
76
+ "organizations.get": crmOperation("organizations", "get"),
77
+ "organizations.create": crmOperation("organizations", "create"),
78
+ "organizations.update": crmOperation("organizations", "update"),
79
+ "activities.list": crmOperation("activities", "list"),
80
+ "activities.get": crmOperation("activities", "get"),
81
+ "activities.create": crmOperation("activities", "create"),
82
+ "activities.update": crmOperation("activities", "update"),
83
+ "leads.list": crmOperation("leads", "list"),
84
+ "leads.get": crmOperation("leads", "get"),
85
+ "leads.create": crmOperation("leads", "create"),
86
+ "leads.update": crmOperation("leads", "update"),
87
+ "pipelines.list": crmOperation("pipelines", "list"),
88
+ "pipelines.get": crmOperation("pipelines", "get"),
89
+ "profile.read": { ...profile, request(input, settings, data) {
90
+ const request = profile.request(input, settings);
91
+ return { ...request, url: data ? `${companyApiDomain(data.apiDomain)}/api/v1/users/me` : request.url };
92
+ } }
93
+ }
94
+ });
95
+ export { pipedriveProvider };
@@ -0,0 +1,20 @@
1
+ import { polarDefinition } from "../shared/tokens.js";
2
+ import { jsonOperation } from "./jsonOperation.js";
3
+
4
+ const origins = { sandbox: "https://sandbox-api.polar.sh", production: "https://api.polar.sh" };
5
+ const polarProvider = Object.freeze({
6
+ ...polarDefinition, apiOrigins: Object.values(origins),
7
+ apiKey: { headers: (key) => ({ Authorization: `Bearer ${key}` }) },
8
+ checkOperation: "products.list",
9
+ operations: {
10
+ "products.list": jsonOperation((settings) => `${origins[settings.environment]}/v1/products/`, {
11
+ page: { type: "integer", min: 1, max: 2147483647, defaultTo: 1 },
12
+ limit: { type: "integer", min: 1, max: 100, defaultTo: 10 },
13
+ query: { type: "string", maxLength: 1024 },
14
+ is_archived: { type: "boolean" },
15
+ is_recurring: { type: "boolean" }
16
+ }, (result) => Array.isArray(result?.items) && Number.isInteger(result.pagination?.total_count) &&
17
+ result.pagination.total_count >= 0 && Number.isInteger(result.pagination.max_page) && result.pagination.max_page >= 0)
18
+ }
19
+ });
20
+ export { polarProvider };
@@ -0,0 +1,44 @@
1
+ import { ConnectorError } from "@jskit-ai/connectors-core/server";
2
+ import { posthogDefinition } from "../shared/posthog.js";
3
+ import { jsonOperation } from "./jsonOperation.js";
4
+
5
+ const origin = (settings) => `https://${settings.region}.i.posthog.com`;
6
+ const distinctId = { type: "string", required: true, minLength: 1, maxLength: 200 };
7
+ const posthogProvider = Object.freeze({
8
+ ...posthogDefinition,
9
+ apiOrigins: (settings) => [origin(settings)],
10
+ apiKey: { bodyParameter: "api_key", headers: (token) => {
11
+ if (!/^phc_[a-zA-Z0-9_-]+$/u.test(token)) {
12
+ throw new ConnectorError("connector_binding_missing", "Use the public PostHog project token starting with phc_.");
13
+ }
14
+ return { "User-Agent": "jskit-connectors/0.1.0 (posthog-node/compatible)" };
15
+ } },
16
+ checkOperation: "flags.evaluate",
17
+ operations: {
18
+ "flags.evaluate": jsonOperation((settings) => `${origin(settings)}/flags?v=2`, {
19
+ distinct_id: distinctId,
20
+ groups: { type: "object", additionalProperties: true },
21
+ person_properties: { type: "object", additionalProperties: true }
22
+ }, (result) => {
23
+ if (!result?.flags || typeof result.flags !== "object" || Array.isArray(result.flags) ||
24
+ typeof result.errorsWhileComputingFlags !== "boolean" ||
25
+ (result.quotaLimited !== undefined && (!Array.isArray(result.quotaLimited) || !result.quotaLimited.every((item) => typeof item === "string")))) return false;
26
+ if (result.quotaLimited?.includes("feature_flags")) {
27
+ throw new ConnectorError("connector_quota_limited", "PostHog's feature flag quota has been reached.", { statusCode: 429 });
28
+ }
29
+ if (result.errorsWhileComputingFlags) {
30
+ throw new ConnectorError("connector_provider_failed", "PostHog could not evaluate all requested flags.", { statusCode: 502 });
31
+ }
32
+ return Object.values(result.flags).every((flag) => flag && typeof flag.enabled === "boolean" &&
33
+ (flag.variant === undefined || typeof flag.variant === "string"));
34
+ }, "POST"),
35
+ "events.capture": jsonOperation((settings) => `${origin(settings)}/i/v0/e/`, {
36
+ event: { type: "string", required: true, minLength: 1, maxLength: 200 },
37
+ distinct_id: distinctId,
38
+ properties: { type: "object", additionalProperties: true, defaultTo: {},
39
+ validator: (value) => !Object.hasOwn(value, "token") && !Object.hasOwn(value, "distinct_id") || "Set the event identity through distinct_id; properties cannot override its token or identity." }
40
+ }, (result) => result?.status === "Ok" &&
41
+ (result.quota_limited === undefined || Array.isArray(result.quota_limited) && result.quota_limited.every((item) => typeof item === "string")), "POST")
42
+ }
43
+ });
44
+ export { posthogProvider };
@@ -0,0 +1,42 @@
1
+ import { createSchema } from "json-rest-schema";
2
+ import { validateSchemaPayload } from "@jskit-ai/kernel/shared/validators";
3
+ import { prestashopDefinition } from "../shared/prestashop.js";
4
+
5
+ const pageSchema = createSchema({
6
+ offset: { type: "integer", min: 0, max: 1000000, defaultTo: 0 },
7
+ limit: { type: "integer", min: 1, max: 100, defaultTo: 20 },
8
+ language: { type: "integer", min: 1, max: 2147483647 }
9
+ });
10
+
11
+ function listOperation(resource) {
12
+ return {
13
+ scopes: [],
14
+ request(input, settings) {
15
+ const values = validateSchemaPayload({ schema: pageSchema, mode: "replace" }, input, { statusCode: 422 });
16
+ const url = new URL(`${settings.siteUrl.replace(/\/+$/u, "")}/api/${resource}`);
17
+ url.searchParams.set("output_format", "JSON");
18
+ url.searchParams.set("display", "full");
19
+ url.searchParams.set("sort", "[id_ASC]");
20
+ url.searchParams.set("limit", `${values.offset},${values.limit}`);
21
+ if (values.language !== undefined) url.searchParams.set("language", String(values.language));
22
+ return { method: "GET", url: url.href };
23
+ },
24
+ validateResult(result) {
25
+ // PrestaShop's JSON writer emits [] when no resource nodes were rendered.
26
+ if (Array.isArray(result)) return result.length === 0;
27
+ return Boolean(result && !result.errors && Array.isArray(result[resource]) && result[resource].every((record) =>
28
+ (typeof record?.id === "string" && /^[1-9]\d*$/u.test(record.id)) ||
29
+ (Number.isSafeInteger(record?.id) && record.id > 0)));
30
+ }
31
+ };
32
+ }
33
+
34
+ const prestashopProvider = Object.freeze({
35
+ ...prestashopDefinition,
36
+ apiOrigins: (settings) => [new URL(settings.siteUrl).origin],
37
+ apiKey: { headers: (key) => ({ Authorization: `Basic ${Buffer.from(`${key}:`).toString("base64")}` }) },
38
+ checkOperation: "products.list",
39
+ operations: { "products.list": listOperation("products"), "orders.list": listOperation("orders") }
40
+ });
41
+
42
+ export { prestashopProvider };
@@ -0,0 +1,42 @@
1
+ import { createSchema } from "json-rest-schema";
2
+ import { validateSchemaPayload } from "@jskit-ai/kernel/shared/validators";
3
+ import { replicateDefinition } from "../shared/tokens.js";
4
+ import { jsonOperation } from "./jsonOperation.js";
5
+
6
+ const identifier = { type: "string", required: true, minLength: 1, maxLength: 200, pattern: "^[A-Za-z0-9_-]+$" };
7
+ const modelFields = { owner: identifier, name: identifier };
8
+ const modelInput = { type: "object", required: true, additionalProperties: true,
9
+ validator: (value) => Buffer.byteLength(JSON.stringify(value)) <= 262144 || "Model input must fit within 256 KiB; use file URLs for larger inputs." };
10
+ const predictionResult = (result) => typeof result?.id === "string" &&
11
+ ["starting", "processing", "succeeded", "failed", "canceled"].includes(result.status);
12
+ function predictionOperation(fields, method, destination, validateResult = predictionResult) {
13
+ const schema = createSchema(fields);
14
+ return { scopes: [], request(input) {
15
+ const values = validateSchemaPayload({ schema, mode: "replace" }, input, { statusCode: 422 });
16
+ const { owner, name, id, ...body } = values;
17
+ return { method, url: `https://api.replicate.com/v1/${destination(values)}`,
18
+ ...(method === "POST" ? { body } : {}) };
19
+ }, validateResult };
20
+ }
21
+
22
+ const replicateProvider = Object.freeze({
23
+ ...replicateDefinition, apiOrigins: ["https://api.replicate.com"],
24
+ apiKey: { headers: (key) => ({ Authorization: `Bearer ${key}` }) },
25
+ checkOperation: "account.read",
26
+ operations: {
27
+ "account.read": jsonOperation("https://api.replicate.com/v1/account", {},
28
+ (result) => ["user", "organization"].includes(result?.type) && typeof result.username === "string"),
29
+ "models.get": predictionOperation(modelFields, "GET", ({ owner, name }) => `models/${owner}/${name}`,
30
+ (result) => typeof result?.name === "string" && typeof result.owner === "string"),
31
+ "predictions.create": predictionOperation({ version: { type: "string", required: true,
32
+ pattern: "^(?:[A-Za-z0-9_-]+/[A-Za-z0-9_-]+:)?[a-f0-9]{64}$" }, input: modelInput },
33
+ "POST", () => "predictions"),
34
+ "models.predict": predictionOperation({ ...modelFields, input: modelInput }, "POST",
35
+ ({ owner, name }) => `models/${owner}/${name}/predictions`),
36
+ "predictions.get": predictionOperation({ id: identifier }, "GET", ({ id }) => `predictions/${id}`),
37
+ "predictions.cancel": predictionOperation({ id: identifier }, "POST", ({ id }) => `predictions/${id}/cancel`),
38
+ "hardware.list": jsonOperation("https://api.replicate.com/v1/hardware", {},
39
+ (result) => Array.isArray(result) && result.every((item) => typeof item?.name === "string" && typeof item.sku === "string"))
40
+ }
41
+ });
42
+ export { replicateProvider };
@@ -0,0 +1,93 @@
1
+ import { createSchema } from "json-rest-schema";
2
+ import { validateSchemaPayload } from "@jskit-ai/kernel/shared/validators";
3
+ import { resendDefinition } from "../shared/definitions.js";
4
+
5
+ const pagination = createSchema({
6
+ limit: { type: "integer", min: 1, max: 100, defaultTo: 20 },
7
+ after: { type: "string", minLength: 1, maxLength: 200 }
8
+ });
9
+
10
+ const email = createSchema({
11
+ from: { type: "string", required: true, minLength: 1, maxLength: 320, pattern: "^[^\\r\\n]+$" },
12
+ to: { type: "array", required: true,
13
+ validator: (value) => (value.length >= 1 && value.length <= 50) || "Provide between 1 and 50 recipients.",
14
+ items: { type: "string", minLength: 1, maxLength: 320, pattern: "^[^\\s@]+@[^\\s@]+$" } },
15
+ subject: { type: "string", required: true, minLength: 1, maxLength: 998, pattern: "^[^\\r\\n]+$" },
16
+ text: { type: "string", required: true, noTrim: true, minLength: 1, maxLength: 1000000 },
17
+ idempotencyKey: { type: "string", required: true, minLength: 1, maxLength: 256, pattern: "^[A-Za-z0-9_./:-]+$" }
18
+ });
19
+
20
+ const resourceId = { type: "string", required: true, minLength: 1, maxLength: 200, pattern: "^[A-Za-z0-9_-]+$" };
21
+ const shortText = { type: "string", minLength: 1, maxLength: 1000, pattern: "^[^\\r\\n]+$" };
22
+ const emailAddress = { type: "string", required: true, maxLength: 320, pattern: "^[^\\s@]+@[^\\s@]+$" };
23
+ const listFields = { limit: { type: "integer", min: 1, max: 100, defaultTo: 20 },
24
+ after: { type: "string", minLength: 1, maxLength: 200 } };
25
+ const broadcastFields = { segment_id: resourceId, from: { ...shortText, required: true, maxLength: 320 },
26
+ subject: { ...shortText, required: true, maxLength: 998 }, name: shortText,
27
+ html: { type: "string", required: true, noTrim: true, minLength: 1, maxLength: 1000000,
28
+ validator: (value) => value.includes("{{{RESEND_UNSUBSCRIBE_URL}}}") || "Include {{{RESEND_UNSUBSCRIBE_URL}}} in the broadcast HTML." },
29
+ text: { type: "string", noTrim: true, maxLength: 1000000 }, preview_text: shortText };
30
+ const hasId = (result) => typeof result?.id === "string" && result.id.length > 0;
31
+ const membershipResult = (result) => result?.object === "contact_segment" && typeof result.contact_id === "string" && typeof result.segment_id === "string";
32
+ const listResult = (result) => result?.object === "list" && Array.isArray(result.data);
33
+ // Fixed provider routes; the application authorizes each named operation before HTTP.
34
+ function marketingOperation(fields, method, destination, validateResult = hasId, draft = false) {
35
+ const schema = createSchema(fields);
36
+ return { scopes: [], request(input) {
37
+ const values = validateSchemaPayload({ schema, mode: "replace" }, input, { statusCode: 422 });
38
+ const { id, segmentId, ...body } = values;
39
+ const url = new URL(`https://api.resend.com/${destination(values)}`);
40
+ if (method === "GET") {
41
+ for (const [key, value] of Object.entries(body)) url.searchParams.set(key, String(value));
42
+ return { method, url: url.href };
43
+ }
44
+ return { method, url: url.href, ...(method === "DELETE" ? {} : { body: draft ? { ...body, send: false } : body }) };
45
+ }, validateResult };
46
+ }
47
+
48
+ const resendProvider = Object.freeze({
49
+ ...resendDefinition,
50
+ apiOrigins: ["https://api.resend.com"],
51
+ apiKey: { headers: (key) => ({ Authorization: `Bearer ${key}` }) },
52
+ checkOperation: "domains.list",
53
+ operations: {
54
+ "segments.list": marketingOperation(listFields, "GET", () => "segments", listResult),
55
+ "segments.create": marketingOperation({ name: { ...shortText, required: true } }, "POST", () => "segments"),
56
+ "contacts.list": marketingOperation({ ...listFields, segment_id: { ...resourceId, required: false } }, "GET", () => "contacts", listResult),
57
+ "contacts.get": marketingOperation({ id: resourceId }, "GET", ({ id }) => `contacts/${id}`),
58
+ "contacts.create": marketingOperation({ email: emailAddress, first_name: shortText, last_name: shortText,
59
+ unsubscribed: { type: "boolean", required: true },
60
+ segments: { type: "array", validator: (value) => value.length <= 100 || "Provide at most 100 segments.",
61
+ items: { type: "object", properties: { id: resourceId } } } }, "POST", () => "contacts"),
62
+ "contacts.update": marketingOperation({ id: resourceId, unsubscribed: { type: "boolean", required: true }, first_name: shortText, last_name: shortText },
63
+ "PATCH", ({ id }) => `contacts/${id}`),
64
+ "contacts.addSegment": marketingOperation({ id: resourceId, segmentId: resourceId }, "POST", ({ id, segmentId }) => `contacts/${id}/segments/${segmentId}`, membershipResult),
65
+ "contacts.removeSegment": marketingOperation({ id: resourceId, segmentId: resourceId }, "DELETE", ({ id, segmentId }) => `contacts/${id}/segments/${segmentId}`, (result) => membershipResult(result) && result.deleted === true),
66
+ "broadcasts.create": marketingOperation(broadcastFields, "POST", () => "broadcasts", hasId, true),
67
+ "broadcasts.get": marketingOperation({ id: resourceId }, "GET", ({ id }) => `broadcasts/${id}`),
68
+ "broadcasts.list": marketingOperation(listFields, "GET", () => "broadcasts", listResult),
69
+ "broadcasts.update": marketingOperation({ id: resourceId, ...broadcastFields }, "PATCH", ({ id }) => `broadcasts/${id}`),
70
+ "broadcasts.send": marketingOperation({ id: resourceId }, "POST", ({ id }) => `broadcasts/${id}/send`),
71
+ "domains.get": marketingOperation({ id: resourceId }, "GET", ({ id }) => `domains/${id}`),
72
+ "emails.send": {
73
+ scopes: [],
74
+ request(input) {
75
+ const { idempotencyKey, ...body } = validateSchemaPayload({ schema: email, mode: "replace" }, input, { statusCode: 422 });
76
+ return { method: "POST", url: "https://api.resend.com/emails",
77
+ headers: { "Idempotency-Key": idempotencyKey }, body };
78
+ },
79
+ validateResult: (result) => typeof result?.id === "string" && result.id.length > 0
80
+ },
81
+ "domains.list": {
82
+ scopes: [],
83
+ request(input) {
84
+ const query = validateSchemaPayload({ schema: pagination, mode: "replace" }, input, { statusCode: 422 });
85
+ const url = new URL("https://api.resend.com/domains");
86
+ for (const [name, value] of Object.entries(query)) url.searchParams.set(name, String(value));
87
+ return { method: "GET", url: url.href };
88
+ },
89
+ validateResult: (result) => result?.object === "list" && Array.isArray(result.data) && typeof result.has_more === "boolean"
90
+ }
91
+ }
92
+ });
93
+ export { resendProvider };