mirror of
https://github.com/simstudioai/sim.git
synced 2026-09-24 15:45:35 +08:00
* feat(google-appsheet): add Google AppSheet integration
- 4 tools (find/add/edit/delete rows) against the AppSheet Action API
- API key auth via Application Access Key (no OAuth/scopes needed)
- Block with operation dropdown, region selector, and Selector expression support
- Generated docs
* improvement(google-appsheet): harden response parsing, add wand config and skills
- Guard against empty/non-JSON AppSheet response bodies (Delete may return no body)
- Add wandConfig to the Selector field for AI-assisted expression generation
- Add 3 skills grounded in attested AppSheet/Zapier automation patterns
- Tighten json output descriptions to describe inner shape
* fix(google-appsheet): validate region against allow-list, encode appId, validate rows shape
- Reject unrecognized region values instead of interpolating them into the
request host (a caller could otherwise redirect the Application Access
Key to an arbitrary domain)
- URL-encode appId, not just tableName, in the Action endpoint path
- Reject non-array Rows input in tools.config.params instead of forwarding
a single object to the AppSheet Action API
- Drop the mismatched json-object generationType on the rows wand config
(that enricher appends "must start with { and end with }", which
conflicts with the JSON-array shape the field expects)
- Add utils.test.ts covering region validation and response-body parsing
* docs(google-appsheet): add manual intro/getting-started section
Match the MANUAL-CONTENT convention used by other integration docs
(Airtable, Ahrefs, Google PageSpeed) — an overview of the service, what
the Sim integration lets agents do, and how to get an Application
Access Key.
* docs: sync generated integration docs with current source
Regenerate docs for integrations whose tools/blocks changed upstream
without a matching docs regen (ahrefs, algolia, amplitude, brex, clerk,
gong, hex, langsmith, loops, onepassword, sendgrid, sharepoint,
similarweb, supabase, tailscale, trello, vercel, wordpress), plus the
integrations.json catalog.
37 lines
1.5 KiB
TypeScript
37 lines
1.5 KiB
TypeScript
const DEFAULT_REGION = 'www'
|
|
const ALLOWED_REGIONS = new Set(['www', 'eu', 'asia-southeast'])
|
|
|
|
/**
|
|
* Builds the AppSheet API Action endpoint URL for a given app/table/region.
|
|
* Region defaults to the global `www.appsheet.com` domain when unset, and is
|
|
* validated against the known AppSheet regions since it is interpolated into
|
|
* the request host — an unvalidated value would let a caller redirect the
|
|
* Application Access Key to an arbitrary host.
|
|
*/
|
|
export function buildAppsheetActionUrl(appId: string, tableName: string, region?: string): string {
|
|
const trimmedRegion = (region || DEFAULT_REGION).trim()
|
|
if (!ALLOWED_REGIONS.has(trimmedRegion)) {
|
|
throw new Error(
|
|
`Invalid AppSheet region "${trimmedRegion}". Must be one of: ${Array.from(ALLOWED_REGIONS).join(', ')}.`
|
|
)
|
|
}
|
|
const host = `${trimmedRegion}.appsheet.com`
|
|
return `https://${host}/api/v2/apps/${encodeURIComponent(appId.trim())}/tables/${encodeURIComponent(tableName.trim())}/Action`
|
|
}
|
|
|
|
/**
|
|
* Safely reads an AppSheet API response body. AppSheet does not consistently
|
|
* document whether every Action returns a JSON body (e.g. Delete may return an
|
|
* empty body on some accounts), so this avoids `response.json()` throwing on
|
|
* empty or non-JSON content.
|
|
*/
|
|
export async function readAppsheetResponseBody(response: Response): Promise<Record<string, any>> {
|
|
const text = await response.text()
|
|
if (!text) return {}
|
|
try {
|
|
return JSON.parse(text)
|
|
} catch {
|
|
return { message: text }
|
|
}
|
|
}
|