@jskit-ai/connectors-catalog 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +192 -0
- package/docs/ai-upstream-notices.md +51 -0
- package/docs/ai.md +191 -0
- package/docs/airtable.md +130 -0
- package/docs/algolia.md +190 -0
- package/docs/amazon-redshift.md +229 -0
- package/docs/amplitude.md +210 -0
- package/docs/apify.md +162 -0
- package/docs/apollo-io.md +200 -0
- package/docs/asana.md +126 -0
- package/docs/ashby.md +188 -0
- package/docs/atlassian.md +224 -0
- package/docs/attention.md +162 -0
- package/docs/aws-athena.md +150 -0
- package/docs/aws-credentials.md +75 -0
- package/docs/aws-s3.md +193 -0
- package/docs/bigquery.md +146 -0
- package/docs/brevo.md +122 -0
- package/docs/calendly.md +158 -0
- package/docs/canva.md +191 -0
- package/docs/chargebee.md +192 -0
- package/docs/clay.md +194 -0
- package/docs/clickhouse.md +242 -0
- package/docs/confidence-exp.md +74 -0
- package/docs/confidence-flags.md +75 -0
- package/docs/confidence-oauth.md +137 -0
- package/docs/contentful.md +123 -0
- package/docs/databricks.md +180 -0
- package/docs/dbt-semantic-layer.md +175 -0
- package/docs/elevenlabs.md +102 -0
- package/docs/figma.md +132 -0
- package/docs/firebase-cloud-messaging.md +262 -0
- package/docs/firecrawl.md +137 -0
- package/docs/fireflies.md +95 -0
- package/docs/fireworks-ai.md +53 -0
- package/docs/gatewayapi.md +113 -0
- package/docs/gemini-enterprise.md +224 -0
- package/docs/github-api.md +133 -0
- package/docs/gitlab-api.md +138 -0
- package/docs/gmail.md +133 -0
- package/docs/gong.md +205 -0
- package/docs/google-ads.md +156 -0
- package/docs/google-analytics.md +202 -0
- package/docs/google-docs.md +105 -0
- package/docs/google-drive.md +108 -0
- package/docs/google-maps-platform.md +208 -0
- package/docs/google-oauth.md +123 -0
- package/docs/google-search-console.md +124 -0
- package/docs/google-sheets.md +94 -0
- package/docs/google-slides.md +95 -0
- package/docs/granola.md +178 -0
- package/docs/hex.md +161 -0
- package/docs/heygen.md +124 -0
- package/docs/hubspot.md +142 -0
- package/docs/incident-io.md +118 -0
- package/docs/inngest.md +178 -0
- package/docs/klipy.md +149 -0
- package/docs/lexware.md +144 -0
- package/docs/lightspeed.md +193 -0
- package/docs/linear.md +137 -0
- package/docs/linkedin.md +196 -0
- package/docs/logo-dev.md +152 -0
- package/docs/mailgun.md +153 -0
- package/docs/mapbox.md +174 -0
- package/docs/microsoft-excel.md +97 -0
- package/docs/microsoft-fabric.md +249 -0
- package/docs/microsoft-oauth.md +143 -0
- package/docs/microsoft-onedrive.md +76 -0
- package/docs/microsoft-onenote.md +75 -0
- package/docs/microsoft-outlook.md +90 -0
- package/docs/microsoft-powerpoint.md +119 -0
- package/docs/microsoft-sharepoint.md +75 -0
- package/docs/microsoft-teams.md +72 -0
- package/docs/microsoft-word.md +119 -0
- package/docs/miro.md +117 -0
- package/docs/n8n.md +169 -0
- package/docs/notion.md +137 -0
- package/docs/oura.md +161 -0
- package/docs/paddle.md +168 -0
- package/docs/perplexity.md +85 -0
- package/docs/pipedrive.md +120 -0
- package/docs/polar.md +63 -0
- package/docs/posthog.md +227 -0
- package/docs/prestashop.md +151 -0
- package/docs/replicate.md +60 -0
- package/docs/resend.md +153 -0
- package/docs/salesforce.md +234 -0
- package/docs/sanity.md +122 -0
- package/docs/semrush.md +276 -0
- package/docs/sentry.md +112 -0
- package/docs/sevdesk.md +107 -0
- package/docs/shopify.md +206 -0
- package/docs/slack.md +257 -0
- package/docs/snowflake.md +271 -0
- package/docs/storyblok.md +130 -0
- package/docs/stripe.md +77 -0
- package/docs/supabase.md +51 -0
- package/docs/tally.md +105 -0
- package/docs/telegram.md +165 -0
- package/docs/tiktok.md +201 -0
- package/docs/twilio.md +284 -0
- package/docs/twitch.md +428 -0
- package/docs/wave.md +440 -0
- package/docs/wix.md +1249 -0
- package/docs/wiz.md +177 -0
- package/docs/woocommerce.md +400 -0
- package/docs/wordpress-com.md +358 -0
- package/docs/wordpress-self-hosted.md +252 -0
- package/docs/workday.md +292 -0
- package/docs/x-twitter.md +188 -0
- package/docs/xero.md +429 -0
- package/docs/zoho-books.md +214 -0
- package/docs/zoho-crm.md +192 -0
- package/package.json +153 -0
- package/patterns/ai-connections/PATTERN.md +84 -0
- package/patterns/ai-connections/example/ai-model.js +11 -0
- package/patterns/ai-connections/example/perplexity-answer.js +29 -0
- package/patterns/api-key-connection/PATTERN.md +368 -0
- package/patterns/api-key-connection/example/connections.js +18 -0
- package/patterns/api-key-connection/example/integrations.json +19 -0
- package/patterns/assistant-mcp/PATTERN.md +110 -0
- package/patterns/assistant-mcp/example/integrations.json +13 -0
- package/patterns/assistant-mcp-oauth/PATTERN.md +235 -0
- package/patterns/assistant-mcp-oauth/example/integrations.json +102 -0
- package/patterns/aws-storage-queries/PATTERN.md +169 -0
- package/patterns/aws-storage-queries/example/formats/data-formats.js +35 -0
- package/patterns/aws-storage-queries/example/formats/package-lock.json +49 -0
- package/patterns/aws-storage-queries/example/formats/package.json +12 -0
- package/patterns/aws-storage-queries/example/formats/verify-formats.mjs +37 -0
- package/patterns/aws-storage-queries/example/integrations.json +38 -0
- package/patterns/aws-storage-queries/example/s3-transfer.js +34 -0
- package/patterns/event-delivery/PATTERN.md +151 -0
- package/patterns/event-delivery/example/integrations.json +17 -0
- package/patterns/firebase-messaging/PATTERN.md +156 -0
- package/patterns/firebase-messaging/example/server/notifications.js +23 -0
- package/patterns/google-ads-search/PATTERN.md +92 -0
- package/patterns/google-ads-search/example/ads-setup.js +25 -0
- package/patterns/oauth-connection/PATTERN.md +724 -0
- package/patterns/oauth-connection/example/integrations.json +20 -0
- package/patterns/paddle-catalogue/PATTERN.md +78 -0
- package/patterns/paddle-catalogue/example/create-products.js +38 -0
- package/patterns/public-image/PATTERN.md +84 -0
- package/patterns/public-image/example/integrations.json +13 -0
- package/patterns/public-image/example/logo-url.js +16 -0
- package/patterns/redshift-queries/PATTERN.md +150 -0
- package/patterns/redshift-queries/example/integrations.json +33 -0
- package/patterns/source-scanning/PATTERN.md +83 -0
- package/patterns/source-scanning/example/source-scanner.js +13 -0
- package/src/client/firebase-cloud-messaging.js +10 -0
- package/src/client/google-analytics.js +72 -0
- package/src/client/google-maps-platform.js +39 -0
- package/src/client/logo-dev.js +36 -0
- package/src/server/ai.js +46 -0
- package/src/server/airtable.js +67 -0
- package/src/server/algolia.js +63 -0
- package/src/server/amazon-redshift.js +96 -0
- package/src/server/amplitude.js +31 -0
- package/src/server/apify.js +68 -0
- package/src/server/apollo-io.js +85 -0
- package/src/server/asana.js +64 -0
- package/src/server/ashby.js +61 -0
- package/src/server/atlassian.js +32 -0
- package/src/server/attention.js +93 -0
- package/src/server/aws-athena.js +82 -0
- package/src/server/aws-s3.js +49 -0
- package/src/server/awsTransport.js +75 -0
- package/src/server/bigquery.js +97 -0
- package/src/server/brevo.js +97 -0
- package/src/server/calendly.js +77 -0
- package/src/server/canva.js +13 -0
- package/src/server/chargebee.js +88 -0
- package/src/server/clay.js +78 -0
- package/src/server/clickhouse.js +66 -0
- package/src/server/confidence.js +29 -0
- package/src/server/contentful.js +40 -0
- package/src/server/databricks.js +55 -0
- package/src/server/dbt-semantic-layer.js +95 -0
- package/src/server/elevenlabs.js +81 -0
- package/src/server/figma.js +24 -0
- package/src/server/firebase-cloud-messaging.js +111 -0
- package/src/server/firecrawl.js +70 -0
- package/src/server/fireflies.js +31 -0
- package/src/server/fireworks-ai.js +16 -0
- package/src/server/gatewayapi.js +48 -0
- package/src/server/gemini-enterprise.js +47 -0
- package/src/server/github-api.js +90 -0
- package/src/server/gitlab-api.js +67 -0
- package/src/server/gmail.js +60 -0
- package/src/server/gong.js +52 -0
- package/src/server/google-ads-search.js +134 -0
- package/src/server/google-ads.js +80 -0
- package/src/server/google-docs.js +36 -0
- package/src/server/google-drive.js +71 -0
- package/src/server/google-maps-platform.js +90 -0
- package/src/server/google-search-console.js +31 -0
- package/src/server/google-sheets.js +60 -0
- package/src/server/google-slides.js +36 -0
- package/src/server/google.js +61 -0
- package/src/server/granola.js +115 -0
- package/src/server/graphqlOperation.js +15 -0
- package/src/server/hex.js +29 -0
- package/src/server/heygen.js +54 -0
- package/src/server/hubspot.js +85 -0
- package/src/server/incident-io.js +68 -0
- package/src/server/inngest.js +86 -0
- package/src/server/jsonOperation.js +34 -0
- package/src/server/klipy.js +34 -0
- package/src/server/lexware.js +59 -0
- package/src/server/lightspeed.js +82 -0
- package/src/server/linear.js +52 -0
- package/src/server/linkedin.js +74 -0
- package/src/server/mailgun.js +76 -0
- package/src/server/mapbox.js +46 -0
- package/src/server/mcpRegistration.js +41 -0
- package/src/server/mcpTransport.js +60 -0
- package/src/server/microsoft-excel.js +67 -0
- package/src/server/microsoft-fabric.js +81 -0
- package/src/server/microsoft-onedrive.js +58 -0
- package/src/server/microsoft-onenote.js +52 -0
- package/src/server/microsoft-outlook.js +58 -0
- package/src/server/microsoft-powerpoint.js +5 -0
- package/src/server/microsoft-sharepoint.js +46 -0
- package/src/server/microsoft-teams.js +29 -0
- package/src/server/microsoft-word.js +5 -0
- package/src/server/microsoft.js +88 -0
- package/src/server/miro.js +29 -0
- package/src/server/n8n.js +78 -0
- package/src/server/notion.js +76 -0
- package/src/server/oura.js +48 -0
- package/src/server/paddle.js +83 -0
- package/src/server/perplexity.js +15 -0
- package/src/server/pipedrive.js +95 -0
- package/src/server/polar.js +20 -0
- package/src/server/posthog.js +44 -0
- package/src/server/prestashop.js +42 -0
- package/src/server/replicate.js +42 -0
- package/src/server/resend.js +93 -0
- package/src/server/salesforce.js +84 -0
- package/src/server/sanity.js +31 -0
- package/src/server/semrush.js +359 -0
- package/src/server/sentry.js +30 -0
- package/src/server/sevdesk.js +20 -0
- package/src/server/shopify.js +99 -0
- package/src/server/slack.js +143 -0
- package/src/server/snowflake.js +139 -0
- package/src/server/storyblok.js +49 -0
- package/src/server/stripe.js +13 -0
- package/src/server/supabase.js +13 -0
- package/src/server/tally.js +78 -0
- package/src/server/telegram.js +55 -0
- package/src/server/tiktok.js +86 -0
- package/src/server/twilio.js +90 -0
- package/src/server/twitch.js +409 -0
- package/src/server/wave.js +520 -0
- package/src/server/wix.js +1048 -0
- package/src/server/wiz.js +117 -0
- package/src/server/woocommerce.js +412 -0
- package/src/server/wordpress-com.js +236 -0
- package/src/server/wordpress-self-hosted.js +134 -0
- package/src/server/workday.js +136 -0
- package/src/server/x-twitter.js +110 -0
- package/src/server/xero.js +397 -0
- package/src/server/zoho-books.js +90 -0
- package/src/server/zoho-crm.js +89 -0
- package/src/server/zohoOAuth.js +21 -0
- package/src/shared/ai-models.json +8049 -0
- package/src/shared/ai.js +63 -0
- package/src/shared/algolia.js +29 -0
- package/src/shared/amazon-redshift.js +51 -0
- package/src/shared/amplitude.js +28 -0
- package/src/shared/atlassian.js +43 -0
- package/src/shared/aws.js +72 -0
- package/src/shared/canva.js +66 -0
- package/src/shared/chargebee.js +26 -0
- package/src/shared/clickhouse.js +38 -0
- package/src/shared/confidence.js +28 -0
- package/src/shared/databricks.js +33 -0
- package/src/shared/dbt-semantic-layer.js +32 -0
- package/src/shared/definitions.js +140 -0
- package/src/shared/figma.js +21 -0
- package/src/shared/firebase-cloud-messaging.js +45 -0
- package/src/shared/gemini-enterprise.js +33 -0
- package/src/shared/gong.js +33 -0
- package/src/shared/google-ads-search.js +31 -0
- package/src/shared/google-ads.js +28 -0
- package/src/shared/google-maps-platform.js +28 -0
- package/src/shared/google.js +133 -0
- package/src/shared/granola.js +25 -0
- package/src/shared/hex.js +28 -0
- package/src/shared/inngest.js +35 -0
- package/src/shared/lightspeed.js +75 -0
- package/src/shared/linkedin.js +27 -0
- package/src/shared/logo-dev.js +21 -0
- package/src/shared/mapbox.js +38 -0
- package/src/shared/mcp.js +92 -0
- package/src/shared/microsoft-fabric.js +47 -0
- package/src/shared/microsoft.js +231 -0
- package/src/shared/miro.js +27 -0
- package/src/shared/oura.js +23 -0
- package/src/shared/posthog.js +33 -0
- package/src/shared/prestashop.js +23 -0
- package/src/shared/salesforce.js +36 -0
- package/src/shared/semrush.js +24 -0
- package/src/shared/shopify.js +51 -0
- package/src/shared/siteUrl.js +12 -0
- package/src/shared/slack.js +88 -0
- package/src/shared/snowflake.js +55 -0
- package/src/shared/tiktok.js +22 -0
- package/src/shared/tokens.js +747 -0
- package/src/shared/twilio.js +41 -0
- package/src/shared/twitch.js +49 -0
- package/src/shared/wave.js +52 -0
- package/src/shared/wix.js +40 -0
- package/src/shared/wiz.js +41 -0
- package/src/shared/wordpress-com.js +30 -0
- package/src/shared/wordpress.js +69 -0
- package/src/shared/workday.js +50 -0
- package/src/shared/x-twitter.js +19 -0
- package/src/shared/xero.js +46 -0
- package/src/shared/zoho-books.js +39 -0
- package/src/shared/zoho-crm.js +43 -0
- package/src/shared/zoho-regions.js +12 -0
- package/test/ai.test.js +136 -0
- package/test/airtable.test.js +125 -0
- package/test/algolia.test.js +207 -0
- package/test/amazon-redshift.test.js +272 -0
- package/test/amplitude.test.js +239 -0
- package/test/apify.test.js +93 -0
- package/test/apollo-io.test.js +125 -0
- package/test/asana.test.js +99 -0
- package/test/ashby.test.js +97 -0
- package/test/atlassian.test.js +249 -0
- package/test/attention.test.js +79 -0
- package/test/aws.test.js +405 -0
- package/test/brevo.test.js +71 -0
- package/test/calendly.test.js +136 -0
- package/test/canva.test.js +258 -0
- package/test/chargebee.test.js +195 -0
- package/test/clickhouse.test.js +278 -0
- package/test/confidence.test.js +205 -0
- package/test/databricks.test.js +253 -0
- package/test/dbt-semantic-layer.test.js +221 -0
- package/test/designMcp.test.js +336 -0
- package/test/elevenlabs.test.js +52 -0
- package/test/firebase-cloud-messaging.test.js +242 -0
- package/test/firecrawl.test.js +66 -0
- package/test/gemini-enterprise.test.js +218 -0
- package/test/github-api.test.js +167 -0
- package/test/gitlab-api.test.js +160 -0
- package/test/gong.test.js +192 -0
- package/test/google-ads.test.js +350 -0
- package/test/google-maps-platform.test.js +191 -0
- package/test/google.test.js +710 -0
- package/test/granola.test.js +240 -0
- package/test/hex.test.js +253 -0
- package/test/heygen.test.js +121 -0
- package/test/hubspot.test.js +103 -0
- package/test/inngest.test.js +219 -0
- package/test/lightspeed.test.js +250 -0
- package/test/linear.test.js +146 -0
- package/test/linkedin.test.js +243 -0
- package/test/logo-dev.test.js +79 -0
- package/test/mailgun.test.js +107 -0
- package/test/mapbox.test.js +181 -0
- package/test/mcp.test.js +227 -0
- package/test/microsoft-fabric.test.js +258 -0
- package/test/microsoft.test.js +554 -0
- package/test/n8nOAuth.test.js +188 -0
- package/test/notionOAuth.test.js +183 -0
- package/test/oura.test.js +211 -0
- package/test/paddleCatalogue.test.js +51 -0
- package/test/paddlePermissions.test.js +101 -0
- package/test/perplexityComposition.test.js +39 -0
- package/test/pipedriveOAuth.test.js +140 -0
- package/test/posthog.test.js +200 -0
- package/test/prestashop.test.js +207 -0
- package/test/resend.test.js +163 -0
- package/test/salesforce.test.js +276 -0
- package/test/semrush.test.js +479 -0
- package/test/sentry.test.js +35 -0
- package/test/shopify.test.js +247 -0
- package/test/slack.test.js +320 -0
- package/test/snowflake.test.js +391 -0
- package/test/tally.test.js +75 -0
- package/test/telegram.test.js +58 -0
- package/test/tiktok.test.js +243 -0
- package/test/tokens.test.js +1079 -0
- package/test/twilio.test.js +221 -0
- package/test/twitch.test.js +573 -0
- package/test/wave.test.js +678 -0
- package/test/wix.test.js +1099 -0
- package/test/wiz.test.js +185 -0
- package/test/wordpress-com.test.js +469 -0
- package/test/wordpress.test.js +660 -0
- package/test/workday.test.js +314 -0
- package/test/x-twitter.test.js +256 -0
- package/test/xero.test.js +700 -0
- package/test/zoho-books.test.js +253 -0
- package/test/zoho-crm.test.js +223 -0
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"registrations": {},
|
|
4
|
+
"integrations": {
|
|
5
|
+
"files": {
|
|
6
|
+
"provider": "aws-s3",
|
|
7
|
+
"displayName": "Application files",
|
|
8
|
+
"accountMode": "shared",
|
|
9
|
+
"scopes": [
|
|
10
|
+
"read"
|
|
11
|
+
],
|
|
12
|
+
"authentication": {
|
|
13
|
+
"method": "api-key",
|
|
14
|
+
"secretRef": "env:AWS_SECRET_ACCESS_KEY"
|
|
15
|
+
},
|
|
16
|
+
"settings": {
|
|
17
|
+
"region": "ap-southeast-2",
|
|
18
|
+
"bucket": "my-app-files",
|
|
19
|
+
"accessKeyIdRef": "env:AWS_ACCESS_KEY_ID"
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
"queries": {
|
|
23
|
+
"provider": "aws-athena",
|
|
24
|
+
"accountMode": "shared",
|
|
25
|
+
"scopes": [],
|
|
26
|
+
"authentication": {
|
|
27
|
+
"method": "api-key",
|
|
28
|
+
"secretRef": "env:AWS_SECRET_ACCESS_KEY"
|
|
29
|
+
},
|
|
30
|
+
"settings": {
|
|
31
|
+
"region": "ap-southeast-2",
|
|
32
|
+
"accessKeyIdRef": "env:AWS_ACCESS_KEY_ID",
|
|
33
|
+
"workgroup": "reports",
|
|
34
|
+
"resultLocation": "s3://query-results/reports/"
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
// Application-owned composition: service.authorize must approve this exact key
|
|
2
|
+
// for context. The same function works in a Node CLI or application backend.
|
|
3
|
+
// Pass a bounded signal for both signing and the complete response-body read.
|
|
4
|
+
export async function transferS3Object({ service, context, integrationId, key,
|
|
5
|
+
direction, body, signal, fetchImpl = globalThis.fetch }) {
|
|
6
|
+
if (!["download", "upload"].includes(direction)) throw new TypeError("Choose download or upload.");
|
|
7
|
+
if (!signal) throw new TypeError("Supply a transfer cancellation/timeout signal.");
|
|
8
|
+
if (direction === "upload" && !(body instanceof Blob || body instanceof ArrayBuffer || ArrayBuffer.isView(body))) {
|
|
9
|
+
throw new TypeError("Supply a Blob, ArrayBuffer or typed-array upload body.");
|
|
10
|
+
}
|
|
11
|
+
signal.throwIfAborted();
|
|
12
|
+
const signed = await service.invoke({ context, integrationId, signal,
|
|
13
|
+
operation: direction === "upload" ? "objects.uploadUrl" : "objects.downloadUrl",
|
|
14
|
+
input: { key } });
|
|
15
|
+
let response;
|
|
16
|
+
try {
|
|
17
|
+
response = await fetchImpl(signed.url, { method: signed.method,
|
|
18
|
+
...(direction === "upload" ? { body } : {}), signal,
|
|
19
|
+
credentials: "omit", redirect: "error" });
|
|
20
|
+
} catch {
|
|
21
|
+
// Do not expose the URL through a network error/cause or retry a PUT whose
|
|
22
|
+
// outcome is unknown. The app decides whether to inspect and retry later.
|
|
23
|
+
throw new Error(direction === "upload"
|
|
24
|
+
? "Upload interrupted; completion is unknown. Check the object before retrying."
|
|
25
|
+
: "Download interrupted. Request a fresh download when ready.");
|
|
26
|
+
}
|
|
27
|
+
if (!response.ok) {
|
|
28
|
+
await response.body?.cancel().catch(() => {});
|
|
29
|
+
throw new Error(`S3 ${direction} failed (HTTP ${response.status}). Check permissions and URL expiry.`);
|
|
30
|
+
}
|
|
31
|
+
// Keep binary downloads as a stream; the caller must await its consumption
|
|
32
|
+
// before announcing completion. Upload success means S3 acknowledged the PUT.
|
|
33
|
+
return response;
|
|
34
|
+
}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: connectors/event-delivery
|
|
3
|
+
title: Authorized Inngest event delivery with portable files
|
|
4
|
+
summary: Compose the shared connector runtime for event delivery while leaving workflow code and event policy with the application.
|
|
5
|
+
keywords: connectors, integrations, inngest, events, workflows, files, cli
|
|
6
|
+
requires: @jskit-ai/connectors-core, @jskit-ai/connectors-catalog
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Authorized Inngest event delivery with portable files
|
|
10
|
+
|
|
11
|
+
## Use when
|
|
12
|
+
|
|
13
|
+
An existing application or CLI must send an event to Inngest and inspect app
|
|
14
|
+
metadata using separately owned Signing and Event Keys.
|
|
15
|
+
|
|
16
|
+
## Do not use when
|
|
17
|
+
|
|
18
|
+
This fragment does not execute or register workflow functions, implement an
|
|
19
|
+
Inngest serve endpoint, configure schedules or provide application-user login.
|
|
20
|
+
Those concerns belong to the app and its chosen Inngest SDK integration.
|
|
21
|
+
|
|
22
|
+
## Product decisions
|
|
23
|
+
|
|
24
|
+
Choose the connection owner, allowed event names, payload schema and stable
|
|
25
|
+
business operation ID. Decide which authenticated users may trigger each event.
|
|
26
|
+
Determine how the app will reconcile delivery uncertainty and report workflow
|
|
27
|
+
progress independently of the connector's delivery receipt.
|
|
28
|
+
|
|
29
|
+
## Invariants
|
|
30
|
+
|
|
31
|
+
- Configuration and connection state remain text files.
|
|
32
|
+
- Signing and Event Key values remain environment bindings, outside source.
|
|
33
|
+
- Metadata verification never sends an event or verifies the Event Key.
|
|
34
|
+
- Authorization sees the requested event before its Event Key is resolved.
|
|
35
|
+
- An accepted event does not prove a function completed.
|
|
36
|
+
- A cancelled request must not automatically replay a possibly accepted event.
|
|
37
|
+
|
|
38
|
+
## Framework APIs
|
|
39
|
+
|
|
40
|
+
Use the `api-key-connection` pattern's existing composition with
|
|
41
|
+
`providers: [inngestProvider]`, imported from
|
|
42
|
+
`@jskit-ai/connectors-catalog/server/inngest`. The JSKIT library owns validated
|
|
43
|
+
requests, credential selection, responses, cancellation and file grants.
|
|
44
|
+
|
|
45
|
+
## Example files
|
|
46
|
+
|
|
47
|
+
`example/integrations.json` supplies the shared `workflows` slot. Provision
|
|
48
|
+
`INNGEST_SIGNING_KEY` and `INNGEST_EVENT_KEY` in the backend environment and
|
|
49
|
+
use the existing file-store protection and authenticated connection context.
|
|
50
|
+
|
|
51
|
+
```js
|
|
52
|
+
async function applicationConnectionPolicy(context, request) {
|
|
53
|
+
const owner = await workflowAccess.requireConnectionOwner(context, request.integrationId);
|
|
54
|
+
if (request.operation === "events.send") {
|
|
55
|
+
await workflowAccess.requireEventPermission(context, request.input);
|
|
56
|
+
}
|
|
57
|
+
return owner;
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
`workflowAccess` is application-owned policy, not a JSKIT API. It must validate
|
|
62
|
+
allowed names and payload ownership against authenticated state. It must also
|
|
63
|
+
authorize connection management and metadata reads. Return a stable trusted
|
|
64
|
+
`applicationId` and `subjectId`; do not trust owner IDs supplied by a browser.
|
|
65
|
+
|
|
66
|
+
```js
|
|
67
|
+
await connections.connectApiKey({ context, integrationId: "workflows" });
|
|
68
|
+
// In an authorized application action, after validating report ownership:
|
|
69
|
+
const receipt = await connections.invoke({
|
|
70
|
+
context, integrationId: "workflows", operation: "events.send", signal,
|
|
71
|
+
input: {
|
|
72
|
+
name: "app/report.requested",
|
|
73
|
+
id: `app/report.requested:${reportRequestId}`,
|
|
74
|
+
data: { reportRequestId }
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
// Record receipt.ids[0] as delivered; track workflow completion separately.
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
The application supplies `reportRequestId` from its validated business request.
|
|
81
|
+
Inngest's deduplication window is finite; a stable ID is not a permanent
|
|
82
|
+
exactly-once guarantee. Within an Inngest function, use the SDK's documented
|
|
83
|
+
step event-sending primitive so delivery participates in durable execution.
|
|
84
|
+
Do not replace SDK function orchestration with connector calls.
|
|
85
|
+
|
|
86
|
+
## Variation points
|
|
87
|
+
|
|
88
|
+
`settings.branchEnvironment` routes event delivery to a branch and does not
|
|
89
|
+
change metadata query selection. `accountMode: "assistant"` requires the host's
|
|
90
|
+
delegated event authority, including any explicit approval. A trusted operator
|
|
91
|
+
CLI uses the same JSON and library without depending on editor storage.
|
|
92
|
+
|
|
93
|
+
## Verification
|
|
94
|
+
|
|
95
|
+
The provider's focused tests simulate metadata and event replies and use real
|
|
96
|
+
encrypted file storage. The public-editor test exercises the same reference
|
|
97
|
+
and branch settings. This source pattern does not generate or run a sample app;
|
|
98
|
+
live event delivery and SDK function execution remain separate acceptance work.
|
|
99
|
+
|
|
100
|
+
## Avoid
|
|
101
|
+
|
|
102
|
+
Do not expose either key in browser code, send events as a connection probe,
|
|
103
|
+
interpret delivery as completed work, permit arbitrary events through a shared
|
|
104
|
+
public route, or retry after an ambiguous network failure without reconciliation.
|
|
105
|
+
|
|
106
|
+
## Native functions and cron
|
|
107
|
+
|
|
108
|
+
App-owned composition, using the native SDK's current `triggers` option
|
|
109
|
+
([functions](https://www.inngest.com/docs/learn/inngest-functions),
|
|
110
|
+
[cron](https://www.inngest.com/docs/guides/scheduled-functions),
|
|
111
|
+
[serve adapters](https://www.inngest.com/docs/learn/serving-inngest-functions);
|
|
112
|
+
reviewed 2026-09-13). Add `inngest` to the consuming application, not to JSKIT's
|
|
113
|
+
connector package. Resolve the JSON slot's Env references before constructing
|
|
114
|
+
its SDK client; standard names below match the example configuration.
|
|
115
|
+
|
|
116
|
+
```js
|
|
117
|
+
import { Inngest } from "inngest";
|
|
118
|
+
import { fastifyPlugin } from "inngest/fastify";
|
|
119
|
+
|
|
120
|
+
const workflows = new Inngest({ id: "reports", eventKey: process.env.INNGEST_EVENT_KEY });
|
|
121
|
+
const report = workflows.createFunction(
|
|
122
|
+
{ id: "requested-report", triggers: { event: "app/report.requested" } },
|
|
123
|
+
async ({ event, step }) => {
|
|
124
|
+
const id = event.data.reportRequestId;
|
|
125
|
+
if (typeof id !== "string" || !id) throw new Error("Missing report request ID");
|
|
126
|
+
return step.run("render-and-store", () => reports.renderRequestedReport(id));
|
|
127
|
+
}
|
|
128
|
+
);
|
|
129
|
+
const reconcile = workflows.createFunction(
|
|
130
|
+
{ id: "reconcile-reports", triggers: { cron: "TZ=UTC 0 * * * *" } },
|
|
131
|
+
async ({ step }) => step.run("reconcile-due", () => reports.reconcileDueRequests())
|
|
132
|
+
);
|
|
133
|
+
// `fastify` is the app's existing server. The SDK validates signed requests
|
|
134
|
+
// using INNGEST_SIGNING_KEY from the deployed application's environment.
|
|
135
|
+
await fastify.register(fastifyPlugin, { client: workflows, functions: [report, reconcile] });
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
`reports` is the application's business service, not a library API. It loads
|
|
139
|
+
persisted, previously authorized requests, enforces tenant boundaries and makes
|
|
140
|
+
writes safe to retry. Do not trust an event's arbitrary user/tenant identifier
|
|
141
|
+
as authorization. `step.run` may retry failed work; a durable step is not a
|
|
142
|
+
substitute for idempotent business writes. Cron timezone is explicit; choose
|
|
143
|
+
schedules with awareness of daylight-saving behavior.
|
|
144
|
+
|
|
145
|
+
Expose the SDK route through the app's normal server composition, then deploy
|
|
146
|
+
and sync its HTTPS `/api/inngest` URL in the selected Inngest environment.
|
|
147
|
+
Keep the Signing Key private and let the native adapter verify signatures.
|
|
148
|
+
JSKIT CLI users follow the same steps without Vibe64. Other stacks use native
|
|
149
|
+
SDKs where available and the same event name/payload/Env contract; this example
|
|
150
|
+
does not promise an SDK in every language. No function execution, cloud sync
|
|
151
|
+
or generated application is performed by this reference pattern.
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"registrations": {},
|
|
4
|
+
"integrations": {
|
|
5
|
+
"workflows": {
|
|
6
|
+
"provider": "inngest",
|
|
7
|
+
"displayName": "Report workflows",
|
|
8
|
+
"accountMode": "shared",
|
|
9
|
+
"scopes": [],
|
|
10
|
+
"authentication": {
|
|
11
|
+
"method": "api-key",
|
|
12
|
+
"secretRef": "env:INNGEST_SIGNING_KEY"
|
|
13
|
+
},
|
|
14
|
+
"settings": { "eventKeyRef": "env:INNGEST_EVENT_KEY" }
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: connectors/firebase-messaging
|
|
3
|
+
title: Firebase messaging from a CLI or application backend
|
|
4
|
+
summary: Wire service-account grants, file storage, explicit message actions and public browser settings without generating an application.
|
|
5
|
+
keywords: connectors, integrations, firebase, fcm, service-account, jwt, notifications, push, vapid, cli, files
|
|
6
|
+
requires: @jskit-ai/connectors-core, @jskit-ai/connectors-catalog
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Firebase messaging from a CLI or application backend
|
|
10
|
+
|
|
11
|
+
## Use when
|
|
12
|
+
|
|
13
|
+
Use this pattern for an application's Firebase sender. The provider package
|
|
14
|
+
implements the service-account protocol and messaging operations; the core
|
|
15
|
+
implements token persistence, renewal and ownership. The application supplies
|
|
16
|
+
its existing authenticated identity, authorization, runtime directory and Env
|
|
17
|
+
bindings. The CLI uses these same libraries. Do not copy their token manager
|
|
18
|
+
or introduce an editor database.
|
|
19
|
+
|
|
20
|
+
Read the packaged `docs/firebase-cloud-messaging.md` before provisioning. No
|
|
21
|
+
OAuth callback exists for this credential mode. The application owner supplies
|
|
22
|
+
the Firebase project and service account through its own Env bindings.
|
|
23
|
+
|
|
24
|
+
## Do not use when
|
|
25
|
+
|
|
26
|
+
Use another provider contract for Firebase Authentication, Firestore or Cloud
|
|
27
|
+
Storage. This fragment does not provide those services or managed provisioning.
|
|
28
|
+
|
|
29
|
+
## Product decisions
|
|
30
|
+
|
|
31
|
+
Choose the target project, who may send which notifications, and whether the
|
|
32
|
+
application needs browser enrollment or only existing targets. Decide where
|
|
33
|
+
recipient/device associations belong in the application's existing storage.
|
|
34
|
+
|
|
35
|
+
## Invariants
|
|
36
|
+
|
|
37
|
+
Private service-account JSON remains on the server. Configuration stores its
|
|
38
|
+
reference, stable project identity and public settings. Verify before reporting
|
|
39
|
+
Connected; authorize every audience before sending. Preserve the existing file
|
|
40
|
+
store and token lock instead of copying the grant implementation.
|
|
41
|
+
|
|
42
|
+
## Framework APIs
|
|
43
|
+
|
|
44
|
+
Use `parseIntegrationConfiguration`, `createConnectionService`,
|
|
45
|
+
`createEnvironmentReferenceResolver`, `createFileConnectionStore`,
|
|
46
|
+
`createCredentialProtection` and `firebaseCloudMessagingProvider` as shown below.
|
|
47
|
+
The public helper is `firebaseCloudMessagingWebConfiguration`; the standard
|
|
48
|
+
Feature action is `connectors.verifyServiceAccount`.
|
|
49
|
+
|
|
50
|
+
## Example files
|
|
51
|
+
|
|
52
|
+
The example module and inline fragments adapt to the application's existing
|
|
53
|
+
source files. They are source guidance, not a generated application or template
|
|
54
|
+
installation.
|
|
55
|
+
|
|
56
|
+
Adapt this source fragment to the application's existing startup owner:
|
|
57
|
+
|
|
58
|
+
[server/notifications.js](example/server/notifications.js) exports
|
|
59
|
+
`openNotificationConnections({ configurationPath, runtimeDirectory, credentialKey, environment, authorizeConnectionOperation })`.
|
|
60
|
+
It composes the existing libraries and returns the ordinary connection service.
|
|
61
|
+
|
|
62
|
+
`credentialKey` is a private 32-byte `Uint8Array`, loaded from the application's
|
|
63
|
+
secret owner, not a literal in generated source. `runtimeDirectory` is an
|
|
64
|
+
absolute private path outside the repository. `environment` contains the
|
|
65
|
+
service-account JSON string referenced by `integrations.json`; a path to that
|
|
66
|
+
JSON file is not the credential value. An application with its own secret store
|
|
67
|
+
can supply an equivalent `resolveReference` implementation.
|
|
68
|
+
|
|
69
|
+
`authorizeConnectionOperation(context, request)` must obtain the real owner
|
|
70
|
+
from trusted identity and return `{ applicationId, subjectId }` only after
|
|
71
|
+
checking access. Shared senders use an authorized shared subject. Every
|
|
72
|
+
`messages.send` requires checking `request.input.message` against the allowed
|
|
73
|
+
recipient and content. A signed-in user or assistant must not gain arbitrary
|
|
74
|
+
topic broadcasts merely by accessing this integration. Keep public and paid
|
|
75
|
+
project assignments in host policy.
|
|
76
|
+
|
|
77
|
+
## Explicit actions
|
|
78
|
+
|
|
79
|
+
From the existing CLI command or server action, verify the configured sender:
|
|
80
|
+
|
|
81
|
+
```js
|
|
82
|
+
await connections.connectServiceAccount({
|
|
83
|
+
context: trustedContext, integrationId: "push", signal
|
|
84
|
+
});
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
This checks a fixed topic with `validate_only: true`. It does not send a test
|
|
88
|
+
notification. For an actual application message, build a bounded typed payload
|
|
89
|
+
and authorize it before invoking the send operation:
|
|
90
|
+
|
|
91
|
+
```js
|
|
92
|
+
const message = {
|
|
93
|
+
fid: recipientInstallationId,
|
|
94
|
+
notification: { title: "Order ready", body: "Your order is ready." },
|
|
95
|
+
data: { orderId: String(order.id) }
|
|
96
|
+
};
|
|
97
|
+
await connections.invoke({ context: trustedContext, integrationId: "push",
|
|
98
|
+
operation: "messages.validate", input: { message }, signal });
|
|
99
|
+
// Use the application's explicit send action and its authorization policy.
|
|
100
|
+
await connections.invoke({ context: trustedContext, integrationId: "push",
|
|
101
|
+
operation: "messages.send", input: { message }, signal });
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Validation does not authorize the later send and is not a delivery guarantee.
|
|
105
|
+
Use exactly one target: `fid`, existing `token`, `topic` or `condition`. Prefer
|
|
106
|
+
installation IDs when using the current Firebase SDK. Keep the installed SDK's
|
|
107
|
+
enrollment contract consistent; do not mix registration-token and installation
|
|
108
|
+
APIs. No automatic retry should wrap an ambiguous timed-out send. If the product
|
|
109
|
+
needs retry scheduling, implement that behavior in its existing delivery owner.
|
|
110
|
+
|
|
111
|
+
The standard JSKIT Feature is also available through
|
|
112
|
+
`createConnectorsFeature(options)` and `connectors.verifyServiceAccount`.
|
|
113
|
+
Product message operations belong in application actions that call `invoke`;
|
|
114
|
+
never expose an arbitrary authenticated URL or unconstrained provider operation.
|
|
115
|
+
|
|
116
|
+
## Variation points
|
|
117
|
+
|
|
118
|
+
### Browser composition
|
|
119
|
+
|
|
120
|
+
For a configuration with `clientMode: "web"`, use the pure library projection:
|
|
121
|
+
|
|
122
|
+
```js
|
|
123
|
+
import { firebaseCloudMessagingWebConfiguration } from "@jskit-ai/connectors-catalog/client/firebase-cloud-messaging";
|
|
124
|
+
const { firebaseConfig, vapidKey } = firebaseCloudMessagingWebConfiguration(publicPushSettings);
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Supply `firebaseConfig` to the application's Firebase initialization and
|
|
128
|
+
`vapidKey` to its SDK registration call. Current documentation uses
|
|
129
|
+
`register(messaging, { vapidKey })` and `onRegistered(messaging, callback)`;
|
|
130
|
+
verify those exports against the version actually installed before wiring them.
|
|
131
|
+
The callback passes the installation ID to an authenticated app endpoint that
|
|
132
|
+
associates it with the correct user/device. Serve the service worker at the
|
|
133
|
+
app's origin and request notification permission through an explicit UI action.
|
|
134
|
+
The public configuration contains no private service-account data.
|
|
135
|
+
|
|
136
|
+
On a custom-domain change, register the browser on the new origin and replace
|
|
137
|
+
its installation association through the same authorized endpoint. Keep the
|
|
138
|
+
stable application identity and project assignment. The server token exchange
|
|
139
|
+
does not acquire a new OAuth callback just because an app uses another domain.
|
|
140
|
+
|
|
141
|
+
## Verification
|
|
142
|
+
|
|
143
|
+
Use a generated test key and an injected `fetchImpl` fixture. Verify JWT issuer,
|
|
144
|
+
audience, expiry, scope and signature; inspect `validate_only` and payload
|
|
145
|
+
targets; cover missing permissions, malformed receipts and cancellation. Use
|
|
146
|
+
the actual file store to test restart and rotation. Form tests must check
|
|
147
|
+
server/web mode changes, reference rejection, public values and file reload.
|
|
148
|
+
These checks do not prove live delivery or browser subscription. Do not create
|
|
149
|
+
a real project, key, subscription or notification as an incidental test.
|
|
150
|
+
|
|
151
|
+
## Avoid
|
|
152
|
+
|
|
153
|
+
Do not expose service-account JSON to the browser, confuse Firebase API keys
|
|
154
|
+
with private service credentials, or choose the paid project from caller input.
|
|
155
|
+
Do not treat an accepted message receipt as device delivery or automatically
|
|
156
|
+
retry a send whose outcome is unknown.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
|
+
import { parseIntegrationConfiguration } from "@jskit-ai/connectors-core/shared/configuration";
|
|
3
|
+
import { createConnectionService, createEnvironmentReferenceResolver } from "@jskit-ai/connectors-core/server";
|
|
4
|
+
import { createFileConnectionStore, createCredentialProtection } from "@jskit-ai/connectors-core/server/file-storage";
|
|
5
|
+
import { firebaseCloudMessagingProvider } from "@jskit-ai/connectors-catalog/server/firebase-cloud-messaging";
|
|
6
|
+
|
|
7
|
+
export async function openNotificationConnections({
|
|
8
|
+
configurationPath, runtimeDirectory, credentialKey, environment,
|
|
9
|
+
authorizeConnectionOperation
|
|
10
|
+
}) {
|
|
11
|
+
const providers = [firebaseCloudMessagingProvider];
|
|
12
|
+
const configuration = parseIntegrationConfiguration(
|
|
13
|
+
await readFile(configurationPath, "utf8"), { providers }
|
|
14
|
+
);
|
|
15
|
+
const protection = createCredentialProtection({
|
|
16
|
+
keys: { current: credentialKey }, activeKeyId: "current"
|
|
17
|
+
});
|
|
18
|
+
const store = createFileConnectionStore({ directory: runtimeDirectory, protection });
|
|
19
|
+
return createConnectionService({ configuration, providers, store,
|
|
20
|
+
resolveReference: createEnvironmentReferenceResolver(environment),
|
|
21
|
+
authorize: authorizeConnectionOperation
|
|
22
|
+
});
|
|
23
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: connectors/google-ads-search
|
|
3
|
+
title: Existing-account Google Ads Search
|
|
4
|
+
summary: Compose reviewed Search campaigns with project-owned Google OAuth and portable saved plans.
|
|
5
|
+
keywords: google, ads, search, campaigns, conversion, cli, connectors
|
|
6
|
+
requires: @jskit-ai/connectors-core, @jskit-ai/connectors-catalog
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Existing-account Google Ads Search
|
|
10
|
+
|
|
11
|
+
## Use when
|
|
12
|
+
|
|
13
|
+
Use the application's normal configuration, Env resolution, OAuth connection
|
|
14
|
+
store and authenticated administrator policy. This is an optional application
|
|
15
|
+
command composition fragment, not an editor dependency of the runtime library.
|
|
16
|
+
|
|
17
|
+
## Framework APIs
|
|
18
|
+
|
|
19
|
+
```js
|
|
20
|
+
import { createGoogleAdsSearchService } from '@jskit-ai/connectors-catalog/server/google-ads-search';
|
|
21
|
+
const ads = createGoogleAdsSearchService({ connections, configuration, context, integrationId });
|
|
22
|
+
const review = await ads.preview(); // local and Google validation only
|
|
23
|
+
// Only after the administrator reviews it:
|
|
24
|
+
const created = await ads.create(review.reviewId); // starts PAUSED
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
`configuration.extensions.googleAdsSearch[integrationId]` holds the saved plan.
|
|
28
|
+
Validate it with `validateGoogleAdsSearchPlan` from the package's shared
|
|
29
|
+
`google-ads-search` export. Keep OAuth settings separate so campaign edits do not
|
|
30
|
+
invalidate consent. The runtime has no Vibe64 protocol, frontend, Env injection or
|
|
31
|
+
storage owner. CLI apps can call it directly. Normal `connections.authorize` must
|
|
32
|
+
authorize the trusted application's advertising administrator for each operation;
|
|
33
|
+
never accept a subject identity from a request body.
|
|
34
|
+
|
|
35
|
+
For Vibe64, compose `example/ads-setup.js` into the app's existing Integration setup
|
|
36
|
+
command and return exactly one JSON result on stdout. Derive `context` and the
|
|
37
|
+
allowed integration ID from trusted command composition before calling the
|
|
38
|
+
fragment. Keep connection status/connect/reconnect/disconnect operations intact.
|
|
39
|
+
Read the public Vibe64 `application-google-ads.md` command contract when targeting
|
|
40
|
+
that editor. Other frameworks implement its JSON/Env and operation contract with
|
|
41
|
+
their native libraries; they do not execute this JavaScript fragment.
|
|
42
|
+
|
|
43
|
+
The Search recipe supports only non-political manual-CPC campaigns with one ad
|
|
44
|
+
group, phrase keywords and a website conversion goal. Account creation, PMax,
|
|
45
|
+
Demand Gen, billing provisioning and automatic assistant tool attachment are not
|
|
46
|
+
implemented. Google API validation does not establish account approval, website
|
|
47
|
+
readiness or conversion-tag installation. The operator must verify those before
|
|
48
|
+
the separately reviewed launch. Lost write responses are uncertain: inspect the
|
|
49
|
+
provider instead of replaying the operation. Disconnect does not stop ad spend.
|
|
50
|
+
|
|
51
|
+
## Do not use when
|
|
52
|
+
|
|
53
|
+
Do not use this recipe to provision accounts, build PMax/Demand Gen campaigns or
|
|
54
|
+
expose an unrestricted advertising endpoint to unauthenticated app users.
|
|
55
|
+
|
|
56
|
+
## Product decisions
|
|
57
|
+
|
|
58
|
+
Select the existing client account, website lead goal, location/language, budget,
|
|
59
|
+
manual CPC bid and copy. Store them in the saved Search plan, not OAuth settings.
|
|
60
|
+
Confirm non-political advertising and separately approve actual launch/spending.
|
|
61
|
+
|
|
62
|
+
## Invariants
|
|
63
|
+
|
|
64
|
+
The application owns the Google connection, trusted account authorization and
|
|
65
|
+
persistent OAuth grants. Reviews include live account values and the saved plan.
|
|
66
|
+
Creation is paused and atomic; launch rechecks the live review. Do not replay a
|
|
67
|
+
write after an uncertain response. Disconnecting does not pause campaigns.
|
|
68
|
+
|
|
69
|
+
## Example files
|
|
70
|
+
|
|
71
|
+
`example/ads-setup.js` maps the optional editor command to the shared service. It
|
|
72
|
+
contains no HTTP endpoint, credential resolution or trusted-identity inference.
|
|
73
|
+
|
|
74
|
+
## Variation points
|
|
75
|
+
|
|
76
|
+
CLI apps invoke the service directly. App-owned setup commands adapt the same
|
|
77
|
+
service to their host. Other frameworks use native Google APIs and the same
|
|
78
|
+
portable plan/operation semantics; they do not run this JavaScript fragment.
|
|
79
|
+
|
|
80
|
+
## Verification
|
|
81
|
+
|
|
82
|
+
Use controlled provider responses to check precise money strings, targeting,
|
|
83
|
+
OAuth preservation, validate-only review, paused creation, stale-review rejection,
|
|
84
|
+
explicit launch confirmation and no automatic replay of failed writes. Test
|
|
85
|
+
normal application authorization before resolving credentials. Actual Google
|
|
86
|
+
approval and conversion/billing readiness require operator verification.
|
|
87
|
+
|
|
88
|
+
## Avoid
|
|
89
|
+
|
|
90
|
+
Do not put secrets in JSON, stdout or chat. Do not execute conversion snippets in
|
|
91
|
+
the editor, confuse OAuth consent with advertiser approval, or claim live account
|
|
92
|
+
acceptance from fixture tests. Keep larger campaign types outside this recipe.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
// Compose the service in the application's existing authenticated command owner.
|
|
2
|
+
// No stdin value establishes the trusted application/administrator identity.
|
|
3
|
+
export async function dispatchAdsSetup(request, service) {
|
|
4
|
+
if (request?.protocol !== "vibe64.integration-setup.command.v1" || typeof request.requestId !== "string" ||
|
|
5
|
+
!/^[A-Za-z0-9_-]{1,200}$/.test(request.requestId) || !request.ads || Array.isArray(request.ads) || typeof request.ads !== "object") {
|
|
6
|
+
throw new Error("Invalid advertising setup request.");
|
|
7
|
+
}
|
|
8
|
+
const args = request.ads;
|
|
9
|
+
let data;
|
|
10
|
+
switch (request.operation) {
|
|
11
|
+
case "ads-discover": data = await service.discover(args.customerId); break;
|
|
12
|
+
case "ads-targets": data = await service.targets(args.customerId, args.name); break;
|
|
13
|
+
case "ads-conversion": data = await service.createConversion(args); break;
|
|
14
|
+
case "ads-preview": data = await service.preview(); break;
|
|
15
|
+
case "ads-create": data = await service.create(args.reviewId); break;
|
|
16
|
+
case "ads-campaign": data = await service.campaign(args.campaignId); break;
|
|
17
|
+
case "ads-launch": data = await service.launch(args); break;
|
|
18
|
+
case "ads-pause": data = await service.pause(args.campaignId); break;
|
|
19
|
+
case "ads-report": data = await service.report(); break;
|
|
20
|
+
default: throw new Error("Unsupported advertising setup operation.");
|
|
21
|
+
}
|
|
22
|
+
const response = { protocol: request.protocol, requestId: request.requestId, status: "ads", operation: request.operation, data };
|
|
23
|
+
if (Buffer.byteLength(JSON.stringify(response)) > 32768) throw new Error("Advertising result exceeds the editor's display limit. Inspect Google Ads before repeating any write.");
|
|
24
|
+
return response;
|
|
25
|
+
}
|