@agent-native/dispatch 0.15.2 → 0.15.3

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 (43) hide show
  1. package/dist/actions/delete-staged-dataset.d.ts +3 -1
  2. package/dist/actions/delete-staged-dataset.js +3 -26
  3. package/dist/actions/delete-staged-dataset.js.map +1 -1
  4. package/dist/actions/delete-workspace-resource.d.ts +13 -13
  5. package/dist/actions/list-staged-datasets.d.ts +1 -1
  6. package/dist/actions/list-staged-datasets.js +3 -28
  7. package/dist/actions/list-staged-datasets.js.map +1 -1
  8. package/dist/actions/provider-api-catalog.d.ts +6 -4
  9. package/dist/actions/provider-api-catalog.js +3 -17
  10. package/dist/actions/provider-api-catalog.js.map +1 -1
  11. package/dist/actions/provider-api-docs.d.ts +21 -2
  12. package/dist/actions/provider-api-docs.js +6 -51
  13. package/dist/actions/provider-api-docs.js.map +1 -1
  14. package/dist/actions/provider-api-register.d.ts +39 -15
  15. package/dist/actions/provider-api-register.js +4 -193
  16. package/dist/actions/provider-api-register.js.map +1 -1
  17. package/dist/actions/provider-api-request.d.ts +34 -2
  18. package/dist/actions/provider-api-request.js +6 -171
  19. package/dist/actions/provider-api-request.js.map +1 -1
  20. package/dist/actions/query-staged-dataset.d.ts +18 -1
  21. package/dist/actions/query-staged-dataset.d.ts.map +1 -1
  22. package/dist/actions/query-staged-dataset.js +3 -100
  23. package/dist/actions/query-staged-dataset.js.map +1 -1
  24. package/dist/actions/upsert-destination.d.ts +12 -12
  25. package/dist/components/layout/Layout.d.ts.map +1 -1
  26. package/dist/components/layout/Layout.js +26 -64
  27. package/dist/components/layout/Layout.js.map +1 -1
  28. package/package.json +4 -3
  29. package/src/actions/delete-staged-dataset.ts +3 -33
  30. package/src/actions/list-staged-datasets.ts +3 -30
  31. package/src/actions/provider-api-audit.spec.ts +2 -3
  32. package/src/actions/provider-api-catalog.ts +10 -23
  33. package/src/actions/provider-api-docs.ts +19 -68
  34. package/src/actions/provider-api-register.ts +5 -233
  35. package/src/actions/provider-api-request.ts +19 -232
  36. package/src/actions/query-staged-dataset.ts +3 -119
  37. package/src/components/layout/Layout.spec.tsx +7 -11
  38. package/src/components/layout/Layout.tsx +42 -145
  39. package/dist/actions/provider-api-audit.d.ts +0 -7
  40. package/dist/actions/provider-api-audit.d.ts.map +0 -1
  41. package/dist/actions/provider-api-audit.js +0 -74
  42. package/dist/actions/provider-api-audit.js.map +0 -1
  43. package/src/actions/provider-api-audit.ts +0 -88
@@ -1,27 +1,7 @@
1
- import { defineAction } from "@agent-native/core";
2
1
  import { getDbExec } from "@agent-native/core/db";
3
- import { upsertCustomProvider, deleteCustomProvider, listCustomProviders, getCustomProvider, assertCanMutateCustomProviderScope, } from "@agent-native/core/provider-api";
2
+ import { createCustomProviderRegistrationAction } from "@agent-native/core/provider-api/actions/custom-provider-registration";
4
3
  import { getCredentialContext } from "@agent-native/core/server";
5
- import { z } from "zod";
6
- /**
7
- * Resolve the caller's role in a specific org, straight from `org_members`.
8
- *
9
- * `getCredentialContext()` (from `@agent-native/core/server`) only exposes
10
- * `{ userEmail, orgId }` — no role. `getOrgContext()` (from
11
- * `@agent-native/core/org`) resolves role but requires an `H3Event`, which
12
- * `defineAction` handlers are not given. This mirrors the established
13
- * no-event role-lookup idiom already used for org-admin gating inside
14
- * agent-callable/background code (see `isCurrentUserOrgAdmin` in
15
- * `packages/core/src/jobs/tools.ts`, `getViewerOrgRole` in
16
- * `packages/dispatch/src/server/lib/usage-metrics-store.ts`, and the same
17
- * query in `packages/core/src/mcp/actions/service-token-access.ts`) — same
18
- * SQL, same fail-closed-to-null-on-error semantics. Returns null (never an
19
- * org role) on any lookup error or when the caller has no membership row in
20
- * this org.
21
- */
22
4
  async function resolveCallerOrgRole(orgId, email) {
23
- if (!orgId)
24
- return null;
25
5
  try {
26
6
  const client = getDbExec();
27
7
  const { rows } = await client.execute({
@@ -37,41 +17,7 @@ async function resolveCallerOrgRole(orgId, email) {
37
17
  return null;
38
18
  }
39
19
  }
40
- const AuthSchema = z.discriminatedUnion("type", [
41
- z.object({
42
- type: z.literal("none"),
43
- }),
44
- z.object({
45
- type: z.literal("bearer"),
46
- credentialKey: z
47
- .string()
48
- .min(1)
49
- .describe("Name of the credential key (e.g. MY_API_TOKEN). Must already be saved via app secrets — this action never accepts secret values."),
50
- }),
51
- z.object({
52
- type: z.literal("basic"),
53
- usernameKey: z
54
- .string()
55
- .min(1)
56
- .describe("Credential key name for the username/login."),
57
- passwordKey: z
58
- .string()
59
- .min(1)
60
- .describe("Credential key name for the password/secret."),
61
- }),
62
- z.object({
63
- type: z.literal("api-key-header"),
64
- credentialKey: z
65
- .string()
66
- .min(1)
67
- .describe("Credential key name for the API key value."),
68
- headerName: z
69
- .string()
70
- .min(1)
71
- .describe("HTTP header name to send the key in (e.g. X-Api-Key)."),
72
- }),
73
- ]);
74
- export default defineAction({
20
+ export default createCustomProviderRegistrationAction({
75
21
  description: `Register or update a custom API provider so the agent can call it via provider-api-request and look up its docs via provider-api-docs.
76
22
 
77
23
  IMPORTANT — credentials:
@@ -81,142 +27,7 @@ IMPORTANT — credentials:
81
27
  google-service-account and oauth-bearer are NOT supported for custom providers.
82
28
 
83
29
  After registration the provider appears in provider-api-catalog and can be used with provider-api-request.`,
84
- schema: z.object({
85
- operation: z
86
- .enum(["upsert", "delete", "list", "get"])
87
- .default("upsert")
88
- .describe("Operation: upsert (create or update), delete (remove), list (all custom providers), get (single provider)."),
89
- id: z
90
- .string()
91
- .min(1)
92
- .max(64)
93
- .optional()
94
- .describe("Provider slug (e.g. my-api). Lowercase letters, digits, hyphens only. Required for upsert/delete/get."),
95
- label: z
96
- .string()
97
- .min(1)
98
- .max(200)
99
- .optional()
100
- .describe("Human-readable name (e.g. 'My Analytics API'). Required for upsert."),
101
- baseUrl: z
102
- .string()
103
- .url()
104
- .optional()
105
- .describe("Base URL for the API (e.g. https://api.example.com/v1). Required for upsert. Must be a public https/http URL."),
106
- auth: AuthSchema.optional().describe("Auth configuration. Required for upsert. Use type 'none' for public APIs."),
107
- docsUrls: z
108
- .array(z.string().url())
109
- .optional()
110
- .describe("Optional list of documentation URLs for this provider."),
111
- allowedHostSuffixes: z
112
- .array(z.string())
113
- .optional()
114
- .describe("Optional list of additional host suffixes requests may target beyond the base URL origin (e.g. ['example.com'])."),
115
- defaultHeaders: z
116
- .record(z.string(), z.string())
117
- .optional()
118
- .describe("Optional headers to include on every request (e.g. { 'Accept': 'application/json' })."),
119
- notes: z
120
- .string()
121
- .max(1000)
122
- .optional()
123
- .describe("Optional notes about this provider shown in the catalog."),
124
- scope: z
125
- .enum(["user", "org"])
126
- .default("org")
127
- .describe("Whether to store the provider for the current user only ('user') or for the whole workspace ('org')."),
128
- }),
129
- http: false,
130
- run: async ({ operation, id, label, baseUrl, auth, docsUrls, allowedHostSuffixes, defaultHeaders, notes, scope, }) => {
131
- const ctx = getCredentialContext();
132
- if (!ctx) {
133
- throw new Error("provider-api-register requires an authenticated request context.");
134
- }
135
- const scopeId = scope === "org" ? (ctx.orgId ?? ctx.userEmail) : ctx.userEmail;
136
- // Only upsert/delete mutate state; list/get remain readable by any org
137
- // member (scoping org-scoped reads is left as a follow-up — see plan
138
- // 014). Resolve the caller's role in the *target* org (`scopeId`, which
139
- // for scope === "org" is exactly `ctx.orgId`) and enforce owner/admin
140
- // before allowing an org-scoped write. `assertCanMutateCustomProviderScope`
141
- // is the single source of truth for this check and is also enforced a
142
- // second time inside `upsertCustomProvider`/`deleteCustomProvider`
143
- // themselves (defense in depth) — calling it here too gives a clear,
144
- // early error before any other work happens.
145
- //
146
- // When the caller has no active org (`ctx.orgId` is null — a solo user,
147
- // or an app that hasn't wired `resolveOrgId` at all), `scopeId` above
148
- // already collapsed to `ctx.userEmail`: there is no shared org resource
149
- // to protect, and no *other* caller can ever address that same scopeId
150
- // (every other request's fallback is scoped to *its own* email). Treat
151
- // that case like sole ownership of a personal bucket — consistent with
152
- // `org/context.ts`'s auto-created personal org, which also assigns the
153
- // user role "owner" — rather than hard-rejecting scope: "org" (the
154
- // action's own default) for every solo user or org-less app.
155
- let orgRole = null;
156
- if ((operation === "upsert" || operation === "delete") && scope === "org") {
157
- orgRole = ctx.orgId
158
- ? await resolveCallerOrgRole(ctx.orgId, ctx.userEmail)
159
- : "owner";
160
- assertCanMutateCustomProviderScope(scope, scopeId, orgRole);
161
- }
162
- if (operation === "list") {
163
- const providers = await listCustomProviders(scope, scopeId);
164
- return {
165
- providers: providers.map((p) => ({
166
- id: p.id,
167
- label: p.label,
168
- baseUrl: p.baseUrl,
169
- authType: p.auth.type,
170
- docsUrls: p.docsUrls,
171
- notes: p.notes,
172
- updatedAt: p.updatedAt,
173
- })),
174
- count: providers.length,
175
- };
176
- }
177
- if (operation === "get") {
178
- if (!id)
179
- throw new Error("id is required for get operation.");
180
- const provider = await getCustomProvider(scope, scopeId, id);
181
- if (!provider) {
182
- return { found: false, id };
183
- }
184
- return { found: true, provider };
185
- }
186
- if (operation === "delete") {
187
- if (!id)
188
- throw new Error("id is required for delete operation.");
189
- const deleted = await deleteCustomProvider(scope, scopeId, id, orgRole);
190
- return { deleted, id };
191
- }
192
- // upsert
193
- if (!id)
194
- throw new Error("id is required for upsert operation.");
195
- if (!label)
196
- throw new Error("label is required for upsert operation.");
197
- if (!baseUrl)
198
- throw new Error("baseUrl is required for upsert operation.");
199
- if (!auth)
200
- throw new Error("auth is required for upsert operation.");
201
- await upsertCustomProvider({
202
- scope,
203
- scopeId,
204
- id,
205
- label,
206
- baseUrl,
207
- auth,
208
- docsUrls,
209
- allowedHostSuffixes,
210
- defaultHeaders,
211
- notes,
212
- orgRole,
213
- });
214
- return {
215
- registered: true,
216
- id,
217
- label,
218
- message: `Custom provider "${id}" registered. Use provider-api-catalog to inspect it and provider-api-request to call it.`,
219
- };
220
- },
30
+ getContext: getCredentialContext,
31
+ resolveOrgRole: resolveCallerOrgRole,
221
32
  });
222
33
  //# sourceMappingURL=provider-api-register.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"provider-api-register.js","sourceRoot":"","sources":["../../src/actions/provider-api-register.ts"],"names":[],"mappings":"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","sourcesContent":["import { defineAction } from \"@agent-native/core\";\nimport { getDbExec } from \"@agent-native/core/db\";\nimport {\n upsertCustomProvider,\n deleteCustomProvider,\n listCustomProviders,\n getCustomProvider,\n assertCanMutateCustomProviderScope,\n} from \"@agent-native/core/provider-api\";\nimport { getCredentialContext } from \"@agent-native/core/server\";\nimport { z } from \"zod\";\n\n/**\n * Resolve the caller's role in a specific org, straight from `org_members`.\n *\n * `getCredentialContext()` (from `@agent-native/core/server`) only exposes\n * `{ userEmail, orgId }` — no role. `getOrgContext()` (from\n * `@agent-native/core/org`) resolves role but requires an `H3Event`, which\n * `defineAction` handlers are not given. This mirrors the established\n * no-event role-lookup idiom already used for org-admin gating inside\n * agent-callable/background code (see `isCurrentUserOrgAdmin` in\n * `packages/core/src/jobs/tools.ts`, `getViewerOrgRole` in\n * `packages/dispatch/src/server/lib/usage-metrics-store.ts`, and the same\n * query in `packages/core/src/mcp/actions/service-token-access.ts`) — same\n * SQL, same fail-closed-to-null-on-error semantics. Returns null (never an\n * org role) on any lookup error or when the caller has no membership row in\n * this org.\n */\nasync function resolveCallerOrgRole(\n orgId: string | null,\n email: string,\n): Promise<string | null> {\n if (!orgId) return null;\n try {\n const client = getDbExec();\n const { rows } = await client.execute({\n sql: `SELECT role FROM org_members WHERE org_id = ? AND LOWER(email) = ? LIMIT 1`,\n args: [orgId, email.toLowerCase()],\n });\n if (rows.length === 0) return null;\n const role = (rows[0] as { role?: unknown }).role;\n return typeof role === \"string\" && role ? role : null;\n } catch {\n return null;\n }\n}\n\nconst AuthSchema = z.discriminatedUnion(\"type\", [\n z.object({\n type: z.literal(\"none\"),\n }),\n z.object({\n type: z.literal(\"bearer\"),\n credentialKey: z\n .string()\n .min(1)\n .describe(\n \"Name of the credential key (e.g. MY_API_TOKEN). Must already be saved via app secrets — this action never accepts secret values.\",\n ),\n }),\n z.object({\n type: z.literal(\"basic\"),\n usernameKey: z\n .string()\n .min(1)\n .describe(\"Credential key name for the username/login.\"),\n passwordKey: z\n .string()\n .min(1)\n .describe(\"Credential key name for the password/secret.\"),\n }),\n z.object({\n type: z.literal(\"api-key-header\"),\n credentialKey: z\n .string()\n .min(1)\n .describe(\"Credential key name for the API key value.\"),\n headerName: z\n .string()\n .min(1)\n .describe(\"HTTP header name to send the key in (e.g. X-Api-Key).\"),\n }),\n]);\n\nexport default defineAction({\n description: `Register or update a custom API provider so the agent can call it via provider-api-request and look up its docs via provider-api-docs.\n\nIMPORTANT — credentials:\n- This action stores only credential KEY NAMES, never secret values.\n- If the required API key is not yet saved, instruct the user to add it via app Settings → Keys, or use the create-vault-secret action, before calling this action.\n- Supported auth kinds: none, bearer, basic, api-key-header.\n google-service-account and oauth-bearer are NOT supported for custom providers.\n\nAfter registration the provider appears in provider-api-catalog and can be used with provider-api-request.`,\n schema: z.object({\n operation: z\n .enum([\"upsert\", \"delete\", \"list\", \"get\"])\n .default(\"upsert\")\n .describe(\n \"Operation: upsert (create or update), delete (remove), list (all custom providers), get (single provider).\",\n ),\n id: z\n .string()\n .min(1)\n .max(64)\n .optional()\n .describe(\n \"Provider slug (e.g. my-api). Lowercase letters, digits, hyphens only. Required for upsert/delete/get.\",\n ),\n label: z\n .string()\n .min(1)\n .max(200)\n .optional()\n .describe(\n \"Human-readable name (e.g. 'My Analytics API'). Required for upsert.\",\n ),\n baseUrl: z\n .string()\n .url()\n .optional()\n .describe(\n \"Base URL for the API (e.g. https://api.example.com/v1). Required for upsert. Must be a public https/http URL.\",\n ),\n auth: AuthSchema.optional().describe(\n \"Auth configuration. Required for upsert. Use type 'none' for public APIs.\",\n ),\n docsUrls: z\n .array(z.string().url())\n .optional()\n .describe(\"Optional list of documentation URLs for this provider.\"),\n allowedHostSuffixes: z\n .array(z.string())\n .optional()\n .describe(\n \"Optional list of additional host suffixes requests may target beyond the base URL origin (e.g. ['example.com']).\",\n ),\n defaultHeaders: z\n .record(z.string(), z.string())\n .optional()\n .describe(\n \"Optional headers to include on every request (e.g. { 'Accept': 'application/json' }).\",\n ),\n notes: z\n .string()\n .max(1000)\n .optional()\n .describe(\"Optional notes about this provider shown in the catalog.\"),\n scope: z\n .enum([\"user\", \"org\"])\n .default(\"org\")\n .describe(\n \"Whether to store the provider for the current user only ('user') or for the whole workspace ('org').\",\n ),\n }),\n http: false,\n run: async ({\n operation,\n id,\n label,\n baseUrl,\n auth,\n docsUrls,\n allowedHostSuffixes,\n defaultHeaders,\n notes,\n scope,\n }) => {\n const ctx = getCredentialContext();\n if (!ctx) {\n throw new Error(\n \"provider-api-register requires an authenticated request context.\",\n );\n }\n const scopeId =\n scope === \"org\" ? (ctx.orgId ?? ctx.userEmail) : ctx.userEmail;\n\n // Only upsert/delete mutate state; list/get remain readable by any org\n // member (scoping org-scoped reads is left as a follow-up — see plan\n // 014). Resolve the caller's role in the *target* org (`scopeId`, which\n // for scope === \"org\" is exactly `ctx.orgId`) and enforce owner/admin\n // before allowing an org-scoped write. `assertCanMutateCustomProviderScope`\n // is the single source of truth for this check and is also enforced a\n // second time inside `upsertCustomProvider`/`deleteCustomProvider`\n // themselves (defense in depth) — calling it here too gives a clear,\n // early error before any other work happens.\n //\n // When the caller has no active org (`ctx.orgId` is null — a solo user,\n // or an app that hasn't wired `resolveOrgId` at all), `scopeId` above\n // already collapsed to `ctx.userEmail`: there is no shared org resource\n // to protect, and no *other* caller can ever address that same scopeId\n // (every other request's fallback is scoped to *its own* email). Treat\n // that case like sole ownership of a personal bucket — consistent with\n // `org/context.ts`'s auto-created personal org, which also assigns the\n // user role \"owner\" — rather than hard-rejecting scope: \"org\" (the\n // action's own default) for every solo user or org-less app.\n let orgRole: string | null = null;\n if ((operation === \"upsert\" || operation === \"delete\") && scope === \"org\") {\n orgRole = ctx.orgId\n ? await resolveCallerOrgRole(ctx.orgId, ctx.userEmail)\n : \"owner\";\n assertCanMutateCustomProviderScope(scope, scopeId, orgRole);\n }\n\n if (operation === \"list\") {\n const providers = await listCustomProviders(scope, scopeId);\n return {\n providers: providers.map((p) => ({\n id: p.id,\n label: p.label,\n baseUrl: p.baseUrl,\n authType: p.auth.type,\n docsUrls: p.docsUrls,\n notes: p.notes,\n updatedAt: p.updatedAt,\n })),\n count: providers.length,\n };\n }\n\n if (operation === \"get\") {\n if (!id) throw new Error(\"id is required for get operation.\");\n const provider = await getCustomProvider(scope, scopeId, id);\n if (!provider) {\n return { found: false, id };\n }\n return { found: true, provider };\n }\n\n if (operation === \"delete\") {\n if (!id) throw new Error(\"id is required for delete operation.\");\n const deleted = await deleteCustomProvider(scope, scopeId, id, orgRole);\n return { deleted, id };\n }\n\n // upsert\n if (!id) throw new Error(\"id is required for upsert operation.\");\n if (!label) throw new Error(\"label is required for upsert operation.\");\n if (!baseUrl) throw new Error(\"baseUrl is required for upsert operation.\");\n if (!auth) throw new Error(\"auth is required for upsert operation.\");\n\n await upsertCustomProvider({\n scope,\n scopeId,\n id,\n label,\n baseUrl,\n auth,\n docsUrls,\n allowedHostSuffixes,\n defaultHeaders,\n notes,\n orgRole,\n });\n\n return {\n registered: true,\n id,\n label,\n message: `Custom provider \"${id}\" registered. Use provider-api-catalog to inspect it and provider-api-request to call it.`,\n };\n },\n});\n"]}
1
+ {"version":3,"file":"provider-api-register.js","sourceRoot":"","sources":["../../src/actions/provider-api-register.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAClD,OAAO,EAAE,sCAAsC,EAAE,MAAM,sEAAsE,CAAC;AAC9H,OAAO,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AAEjE,KAAK,UAAU,oBAAoB,CACjC,KAAa,EACb,KAAa;IAEb,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;QAC3B,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC;YACpC,GAAG,EAAE,4EAA4E;YACjF,IAAI,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,WAAW,EAAE,CAAC;SACnC,CAAC,CAAC;QACH,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,IAAI,CAAC;QACnC,MAAM,IAAI,GAAI,IAAI,CAAC,CAAC,CAAwB,CAAC,IAAI,CAAC;QAClD,OAAO,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;IACxD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,eAAe,sCAAsC,CAAC;IACpD,WAAW,EAAE;;;;;;;;2GAQ4F;IACzG,UAAU,EAAE,oBAAoB;IAChC,cAAc,EAAE,oBAAoB;CACrC,CAAC,CAAC","sourcesContent":["import { getDbExec } from \"@agent-native/core/db\";\nimport { createCustomProviderRegistrationAction } from \"@agent-native/core/provider-api/actions/custom-provider-registration\";\nimport { getCredentialContext } from \"@agent-native/core/server\";\n\nasync function resolveCallerOrgRole(\n orgId: string,\n email: string,\n): Promise<string | null> {\n try {\n const client = getDbExec();\n const { rows } = await client.execute({\n sql: `SELECT role FROM org_members WHERE org_id = ? AND LOWER(email) = ? LIMIT 1`,\n args: [orgId, email.toLowerCase()],\n });\n if (rows.length === 0) return null;\n const role = (rows[0] as { role?: unknown }).role;\n return typeof role === \"string\" && role ? role : null;\n } catch {\n return null;\n }\n}\n\nexport default createCustomProviderRegistrationAction({\n description: `Register or update a custom API provider so the agent can call it via provider-api-request and look up its docs via provider-api-docs.\n\nIMPORTANT — credentials:\n- This action stores only credential KEY NAMES, never secret values.\n- If the required API key is not yet saved, instruct the user to add it via app Settings → Keys, or use the create-vault-secret action, before calling this action.\n- Supported auth kinds: none, bearer, basic, api-key-header.\n google-service-account and oauth-bearer are NOT supported for custom providers.\n\nAfter registration the provider appears in provider-api-catalog and can be used with provider-api-request.`,\n getContext: getCredentialContext,\n resolveOrgRole: resolveCallerOrgRole,\n});\n"]}
@@ -1,5 +1,37 @@
1
- declare const _default: import("@agent-native/core").ActionDefinition<{
2
- provider: string;
1
+ declare const _default: import("node_modules/@agent-native/core/dist/action.js").ActionDefinition<{
2
+ provider: unknown;
3
+ method?: "DELETE" | "GET" | "HEAD" | "PATCH" | "POST" | "PUT" | undefined;
4
+ path: string;
5
+ query?: unknown;
6
+ headers?: Record<string, unknown> | undefined;
7
+ body?: unknown;
8
+ auth?: "default" | "none" | undefined;
9
+ connectionId?: string | undefined;
10
+ accountId?: string | undefined;
11
+ timeoutMs?: unknown;
12
+ maxBytes?: unknown;
13
+ saveToFile?: string | undefined;
14
+ stageAs?: string | undefined;
15
+ itemsPath?: string | undefined;
16
+ pagination?: {
17
+ nextCursorPath?: string | undefined;
18
+ cursorParam?: string | undefined;
19
+ cursorBodyPath?: string | undefined;
20
+ pageParam?: string | undefined;
21
+ startPage?: unknown;
22
+ offsetParam?: string | undefined;
23
+ pageSize?: unknown;
24
+ maxPages?: unknown;
25
+ } | undefined;
26
+ fetchAllPages?: {
27
+ cursorPath: string;
28
+ cursorParam?: string | undefined;
29
+ cursorBodyPath?: string | undefined;
30
+ itemsPath?: string | undefined;
31
+ maxPages?: unknown;
32
+ } | undefined;
33
+ } | {
34
+ provider: unknown;
3
35
  method?: "DELETE" | "GET" | "HEAD" | "PATCH" | "POST" | "PUT" | undefined;
4
36
  path: string;
5
37
  query?: unknown;
@@ -1,178 +1,13 @@
1
- import { defineAction } from "@agent-native/core";
2
- import { stagingExecuteRequest } from "@agent-native/core/provider-api/staging";
3
- import { getCredentialContext } from "@agent-native/core/server/request-context";
1
+ import { createProviderApiRequestAction, createProviderApiRequestSchema, } from "@agent-native/core/provider-api/actions/provider-api";
4
2
  import { z } from "zod";
5
3
  import { DISPATCH_APP_ID, executeProviderApiRequest, } from "../server/lib/provider-api.js";
6
- import { buildProviderApiAuditSummary } from "./provider-api-audit.js";
7
- const MethodSchema = z.enum(["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD"]);
8
- const PaginationSchema = z
9
- .object({
10
- nextCursorPath: z
11
- .string()
12
- .optional()
13
- .describe("Dot-path in the response JSON where the next cursor/token lives, e.g. 'next_cursor', 'meta.next', or 'nextPageToken'."),
14
- cursorParam: z
15
- .string()
16
- .optional()
17
- .describe("Query parameter name to inject the cursor into the next request. Use cursorBodyPath for APIs that page through POST bodies."),
18
- cursorBodyPath: z
19
- .string()
20
- .optional()
21
- .describe("Dot-path in the JSON request body to set to the next cursor. Use this for POST-body pagination."),
22
- pageParam: z
23
- .string()
24
- .optional()
25
- .describe("Use page-number mode: this query param is incremented on each page."),
26
- startPage: z.coerce
27
- .number()
28
- .int()
29
- .optional()
30
- .describe("Starting page number for pageParam mode (default 1)."),
31
- offsetParam: z
4
+ export default createProviderApiRequestAction({ executeRequest: executeProviderApiRequest }, {
5
+ appId: DISPATCH_APP_ID,
6
+ description: "Make an arbitrary authenticated HTTP request to a shared workspace integration, configured provider API, or custom provider registered via provider-api-register. Use this as the flexible escape hatch when Dispatch needs a provider endpoint, filter, pagination mode, payload, or API version that no canned action models. The request is constrained to the provider host, uses configured credentials automatically, blocks private/internal URLs, and redacts secrets from responses.",
7
+ schema: createProviderApiRequestSchema(z
32
8
  .string()
33
- .optional()
34
- .describe("Use offset mode: this query param is incremented by pageSize on each request."),
35
- pageSize: z.coerce
36
- .number()
37
- .int()
38
- .min(1)
39
- .optional()
40
- .describe("Expected page size for offset increments. Defaults to the actual item count of the first page."),
41
- maxPages: z.coerce
42
- .number()
43
- .int()
44
9
  .min(1)
45
- .max(200)
46
- .optional()
47
- .describe("Maximum pages to fetch server-side (default 50, max 200)."),
48
- })
49
- .optional();
50
- export default defineAction({
51
- description: "Make an arbitrary authenticated HTTP request to a shared workspace integration, configured provider API, or custom provider registered via provider-api-register. Use this as the flexible escape hatch when Dispatch needs a provider endpoint, filter, pagination mode, payload, or API version that no canned action models. The request is constrained to the provider host, uses configured credentials automatically, blocks private/internal URLs, and redacts secrets from responses.",
52
- schema: z.object({
53
- provider: z
54
- .string()
55
- .min(1)
56
- .describe("Provider id to call — built-in (e.g. slack, github, notion, hubspot, gmail, google_drive, google_calendar, granola, stripe, jira) or a custom provider id registered via provider-api-register. Use provider-api-catalog to list available providers."),
57
- method: MethodSchema.default("GET").describe("HTTP method to use."),
58
- path: z
59
- .string()
60
- .min(1)
61
- .describe("Provider API path such as /search.messages, /repos/org/repo/issues, /crm/v3/objects/deals/search, or a full URL on an allowed provider host. Use placeholders from provider-api-catalog when provided."),
62
- query: z
63
- .unknown()
64
- .optional()
65
- .describe("Optional query params as a JSON object/string. Array values produce repeated query params."),
66
- headers: z
67
- .record(z.string(), z.unknown())
68
- .optional()
69
- .describe("Optional extra headers. Unsafe hop-by-hop headers are ignored. Auth headers are injected from stored credentials."),
70
- body: z
71
- .unknown()
72
- .optional()
73
- .describe("Optional request body. Objects/arrays are JSON encoded; strings are sent as-is."),
74
- auth: z
75
- .enum(["default", "none"])
76
- .default("default")
77
- .describe("Use default to inject configured provider auth. Use none only for public provider endpoints that intentionally require no auth."),
78
- connectionId: z
79
- .string()
80
- .optional()
81
- .describe("Optional shared workspace connection id to use when the provider has multiple granted connections."),
82
- accountId: z
83
- .string()
84
- .optional()
85
- .describe("Optional OAuth account id to use for OAuth-backed providers such as Gmail, Google Calendar, or Google Drive."),
86
- timeoutMs: z.coerce
87
- .number()
88
- .int()
89
- .min(1_000)
90
- .max(120_000)
91
- .optional()
92
- .describe("Request timeout in milliseconds. Default 30000, max 120000."),
93
- maxBytes: z.coerce
94
- .number()
95
- .int()
96
- .min(1_000)
97
- .max(4 * 1024 * 1024)
98
- .optional()
99
- .describe("Maximum response bytes to read. Default 1MB, max 4MB. Ignored when saveToFile is set (allows up to 20MB)."),
100
- saveToFile: z
101
- .string()
102
- .optional()
103
- .describe("Workspace file path to save the full response body to instead of returning it in context (e.g. 'analysis/provider-response.json'). When set, returns only a compact summary {savedTo, status, bytes, preview} and allows up to 20MB response. Useful for large datasets that would overflow context."),
104
- stageAs: z
105
- .string()
106
- .min(1)
107
- .optional()
108
- .describe("When set, parse the response as an array of records and write them into a staged dataset with this name. Returns a compact summary instead of the raw body. Re-staging the same name replaces the previous dataset."),
109
- itemsPath: z
110
- .string()
111
- .optional()
112
- .describe("Dot-path to the items array in the response JSON, e.g. 'items', 'results', or 'data'. Omit for auto-detection."),
113
- pagination: PaginationSchema.describe("Pagination config for server-side fetchAll when stageAs is set. Supports cursor (nextCursorPath + cursorParam or cursorBodyPath), page, and offset modes."),
114
- fetchAllPages: z
115
- .object({
116
- cursorPath: z
117
- .string()
118
- .describe("Dot-path in the JSON response body where the next-page cursor lives, e.g. 'meta.next_cursor' or 'pagination.next_page_token'."),
119
- cursorParam: z
120
- .string()
121
- .optional()
122
- .describe("Query parameter name to pass the cursor on subsequent pages, e.g. 'cursor' or 'page_token'. Use cursorBodyPath instead for APIs that put cursors in POST bodies."),
123
- cursorBodyPath: z
124
- .string()
125
- .optional()
126
- .describe("Dot-path in the JSON request body to set to the next cursor. Use for POST-body pagination."),
127
- itemsPath: z
128
- .string()
129
- .optional()
130
- .describe("Dot-path to the items array in each response, e.g. 'results' or 'data.items'. When omitted, the whole response body is appended per page."),
131
- maxPages: z.coerce
132
- .number()
133
- .int()
134
- .min(1)
135
- .max(50)
136
- .optional()
137
- .describe("Maximum pages to fetch. Default 10, max 50. Stops early when the cursor is empty."),
138
- })
139
- .optional()
140
- .describe("Enable cursor-based pagination. After each response, reads cursorPath from the JSON body and re-issues the request with cursorParam or cursorBodyPath set, accumulating items from itemsPath (or whole bodies) until cursor is empty or maxPages is reached. Combine with saveToFile to write the full dataset to a workspace file."),
141
- }),
10
+ .describe("Provider id to call — built-in (e.g. slack, github, notion, hubspot, gmail, google_drive, google_calendar, granola, stripe, jira) or a custom provider id registered via provider-api-register. Use provider-api-catalog to list available providers.")),
142
11
  http: false,
143
- audit: {
144
- recordInputs: false,
145
- target: (args) => ({
146
- type: "provider-api",
147
- id: String(args.provider),
148
- visibility: "private",
149
- }),
150
- summary: (args) => buildProviderApiAuditSummary(args),
151
- },
152
- run: async (args) => {
153
- if (args.stageAs) {
154
- const ctx = getCredentialContext();
155
- if (!ctx) {
156
- throw new Error("No authenticated context for provider API staging.");
157
- }
158
- return stagingExecuteRequest({
159
- provider: args.provider,
160
- method: args.method,
161
- path: args.path,
162
- query: args.query,
163
- headers: args.headers,
164
- body: args.body,
165
- auth: args.auth,
166
- connectionId: args.connectionId,
167
- accountId: args.accountId,
168
- timeoutMs: args.timeoutMs,
169
- maxBytes: args.maxBytes,
170
- stageAs: args.stageAs,
171
- itemsPath: args.itemsPath,
172
- pagination: args.pagination,
173
- }, (reqArgs) => executeProviderApiRequest(reqArgs), { appId: DISPATCH_APP_ID, ownerEmail: ctx.userEmail });
174
- }
175
- return executeProviderApiRequest(args);
176
- },
177
12
  });
178
13
  //# sourceMappingURL=provider-api-request.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"provider-api-request.js","sourceRoot":"","sources":["../../src/actions/provider-api-request.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,qBAAqB,EAAE,MAAM,yCAAyC,CAAC;AAChF,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EACL,eAAe,EACf,yBAAyB,GAC1B,MAAM,+BAA+B,CAAC;AACvC,OAAO,EAAE,4BAA4B,EAAE,MAAM,yBAAyB,CAAC;AAEvE,MAAM,YAAY,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAC;AAE/E,MAAM,gBAAgB,GAAG,CAAC;KACvB,MAAM,CAAC;IACN,cAAc,EAAE,CAAC;SACd,MAAM,EAAE;SACR,QAAQ,EAAE;SACV,QAAQ,CACP,uHAAuH,CACxH;IACH,WAAW,EAAE,CAAC;SACX,MAAM,EAAE;SACR,QAAQ,EAAE;SACV,QAAQ,CACP,6HAA6H,CAC9H;IACH,cAAc,EAAE,CAAC;SACd,MAAM,EAAE;SACR,QAAQ,EAAE;SACV,QAAQ,CACP,iGAAiG,CAClG;IACH,SAAS,EAAE,CAAC;SACT,MAAM,EAAE;SACR,QAAQ,EAAE;SACV,QAAQ,CACP,qEAAqE,CACtE;IACH,SAAS,EAAE,CAAC,CAAC,MAAM;SAChB,MAAM,EAAE;SACR,GAAG,EAAE;SACL,QAAQ,EAAE;SACV,QAAQ,CAAC,sDAAsD,CAAC;IACnE,WAAW,EAAE,CAAC;SACX,MAAM,EAAE;SACR,QAAQ,EAAE;SACV,QAAQ,CACP,+EAA+E,CAChF;IACH,QAAQ,EAAE,CAAC,CAAC,MAAM;SACf,MAAM,EAAE;SACR,GAAG,EAAE;SACL,GAAG,CAAC,CAAC,CAAC;SACN,QAAQ,EAAE;SACV,QAAQ,CACP,gGAAgG,CACjG;IACH,QAAQ,EAAE,CAAC,CAAC,MAAM;SACf,MAAM,EAAE;SACR,GAAG,EAAE;SACL,GAAG,CAAC,CAAC,CAAC;SACN,GAAG,CAAC,GAAG,CAAC;SACR,QAAQ,EAAE;SACV,QAAQ,CAAC,2DAA2D,CAAC;CACzE,CAAC;KACD,QAAQ,EAAE,CAAC;AAEd,eAAe,YAAY,CAAC;IAC1B,WAAW,EACT,+dAA+d;IACje,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC;QACf,QAAQ,EAAE,CAAC;aACR,MAAM,EAAE;aACR,GAAG,CAAC,CAAC,CAAC;aACN,QAAQ,CACP,uPAAuP,CACxP;QACH,MAAM,EAAE,YAAY,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,qBAAqB,CAAC;QACnE,IAAI,EAAE,CAAC;aACJ,MAAM,EAAE;aACR,GAAG,CAAC,CAAC,CAAC;aACN,QAAQ,CACP,wMAAwM,CACzM;QACH,KAAK,EAAE,CAAC;aACL,OAAO,EAAE;aACT,QAAQ,EAAE;aACV,QAAQ,CACP,4FAA4F,CAC7F;QACH,OAAO,EAAE,CAAC;aACP,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC;aAC/B,QAAQ,EAAE;aACV,QAAQ,CACP,mHAAmH,CACpH;QACH,IAAI,EAAE,CAAC;aACJ,OAAO,EAAE;aACT,QAAQ,EAAE;aACV,QAAQ,CACP,iFAAiF,CAClF;QACH,IAAI,EAAE,CAAC;aACJ,IAAI,CAAC,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;aACzB,OAAO,CAAC,SAAS,CAAC;aAClB,QAAQ,CACP,iIAAiI,CAClI;QACH,YAAY,EAAE,CAAC;aACZ,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,QAAQ,CACP,oGAAoG,CACrG;QACH,SAAS,EAAE,CAAC;aACT,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,QAAQ,CACP,8GAA8G,CAC/G;QACH,SAAS,EAAE,CAAC,CAAC,MAAM;aAChB,MAAM,EAAE;aACR,GAAG,EAAE;aACL,GAAG,CAAC,KAAK,CAAC;aACV,GAAG,CAAC,OAAO,CAAC;aACZ,QAAQ,EAAE;aACV,QAAQ,CAAC,6DAA6D,CAAC;QAC1E,QAAQ,EAAE,CAAC,CAAC,MAAM;aACf,MAAM,EAAE;aACR,GAAG,EAAE;aACL,GAAG,CAAC,KAAK,CAAC;aACV,GAAG,CAAC,CAAC,GAAG,IAAI,GAAG,IAAI,CAAC;aACpB,QAAQ,EAAE;aACV,QAAQ,CACP,2GAA2G,CAC5G;QACH,UAAU,EAAE,CAAC;aACV,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,QAAQ,CACP,sSAAsS,CACvS;QACH,OAAO,EAAE,CAAC;aACP,MAAM,EAAE;aACR,GAAG,CAAC,CAAC,CAAC;aACN,QAAQ,EAAE;aACV,QAAQ,CACP,qNAAqN,CACtN;QACH,SAAS,EAAE,CAAC;aACT,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,QAAQ,CACP,gHAAgH,CACjH;QACH,UAAU,EAAE,gBAAgB,CAAC,QAAQ,CACnC,2JAA2J,CAC5J;QACD,aAAa,EAAE,CAAC;aACb,MAAM,CAAC;YACN,UAAU,EAAE,CAAC;iBACV,MAAM,EAAE;iBACR,QAAQ,CACP,+HAA+H,CAChI;YACH,WAAW,EAAE,CAAC;iBACX,MAAM,EAAE;iBACR,QAAQ,EAAE;iBACV,QAAQ,CACP,kKAAkK,CACnK;YACH,cAAc,EAAE,CAAC;iBACd,MAAM,EAAE;iBACR,QAAQ,EAAE;iBACV,QAAQ,CACP,4FAA4F,CAC7F;YACH,SAAS,EAAE,CAAC;iBACT,MAAM,EAAE;iBACR,QAAQ,EAAE;iBACV,QAAQ,CACP,2IAA2I,CAC5I;YACH,QAAQ,EAAE,CAAC,CAAC,MAAM;iBACf,MAAM,EAAE;iBACR,GAAG,EAAE;iBACL,GAAG,CAAC,CAAC,CAAC;iBACN,GAAG,CAAC,EAAE,CAAC;iBACP,QAAQ,EAAE;iBACV,QAAQ,CACP,mFAAmF,CACpF;SACJ,CAAC;aACD,QAAQ,EAAE;aACV,QAAQ,CACP,qUAAqU,CACtU;KACJ,CAAC;IACF,IAAI,EAAE,KAAK;IACX,KAAK,EAAE;QACL,YAAY,EAAE,KAAK;QACnB,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;YACjB,IAAI,EAAE,cAAc;YACpB,EAAE,EAAE,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC;YACzB,UAAU,EAAE,SAAS;SACtB,CAAC;QACF,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,4BAA4B,CAAC,IAAI,CAAC;KACtD;IACD,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE;QAClB,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACjB,MAAM,GAAG,GAAG,oBAAoB,EAAE,CAAC;YACnC,IAAI,CAAC,GAAG,EAAE,CAAC;gBACT,MAAM,IAAI,KAAK,CAAC,oDAAoD,CAAC,CAAC;YACxE,CAAC;YACD,OAAO,qBAAqB,CAC1B;gBACE,QAAQ,EAAE,IAAI,CAAC,QAAQ;gBACvB,MAAM,EAAE,IAAI,CAAC,MAAM;gBACnB,IAAI,EAAE,IAAI,CAAC,IAAI;gBACf,KAAK,EAAE,IAAI,CAAC,KAAK;gBACjB,OAAO,EAAE,IAAI,CAAC,OAAO;gBACrB,IAAI,EAAE,IAAI,CAAC,IAAI;gBACf,IAAI,EAAE,IAAI,CAAC,IAAI;gBACf,YAAY,EAAE,IAAI,CAAC,YAAY;gBAC/B,SAAS,EAAE,IAAI,CAAC,SAAS;gBACzB,SAAS,EAAE,IAAI,CAAC,SAAS;gBACzB,QAAQ,EAAE,IAAI,CAAC,QAAQ;gBACvB,OAAO,EAAE,IAAI,CAAC,OAAO;gBACrB,SAAS,EAAE,IAAI,CAAC,SAAS;gBACzB,UAAU,EAAE,IAAI,CAAC,UAAU;aAC5B,EACD,CAAC,OAAO,EAAE,EAAE,CAAC,yBAAyB,CAAC,OAAO,CAAC,EAC/C,EAAE,KAAK,EAAE,eAAe,EAAE,UAAU,EAAE,GAAG,CAAC,SAAS,EAAE,CACtD,CAAC;QACJ,CAAC;QACD,OAAO,yBAAyB,CAC9B,IAAkE,CACnE,CAAC;IACJ,CAAC;CACF,CAAC,CAAC","sourcesContent":["import { defineAction } from \"@agent-native/core\";\nimport { stagingExecuteRequest } from \"@agent-native/core/provider-api/staging\";\nimport { getCredentialContext } from \"@agent-native/core/server/request-context\";\nimport { z } from \"zod\";\n\nimport {\n DISPATCH_APP_ID,\n executeProviderApiRequest,\n} from \"../server/lib/provider-api.js\";\nimport { buildProviderApiAuditSummary } from \"./provider-api-audit.js\";\n\nconst MethodSchema = z.enum([\"GET\", \"POST\", \"PUT\", \"PATCH\", \"DELETE\", \"HEAD\"]);\n\nconst PaginationSchema = z\n .object({\n nextCursorPath: z\n .string()\n .optional()\n .describe(\n \"Dot-path in the response JSON where the next cursor/token lives, e.g. 'next_cursor', 'meta.next', or 'nextPageToken'.\",\n ),\n cursorParam: z\n .string()\n .optional()\n .describe(\n \"Query parameter name to inject the cursor into the next request. Use cursorBodyPath for APIs that page through POST bodies.\",\n ),\n cursorBodyPath: z\n .string()\n .optional()\n .describe(\n \"Dot-path in the JSON request body to set to the next cursor. Use this for POST-body pagination.\",\n ),\n pageParam: z\n .string()\n .optional()\n .describe(\n \"Use page-number mode: this query param is incremented on each page.\",\n ),\n startPage: z.coerce\n .number()\n .int()\n .optional()\n .describe(\"Starting page number for pageParam mode (default 1).\"),\n offsetParam: z\n .string()\n .optional()\n .describe(\n \"Use offset mode: this query param is incremented by pageSize on each request.\",\n ),\n pageSize: z.coerce\n .number()\n .int()\n .min(1)\n .optional()\n .describe(\n \"Expected page size for offset increments. Defaults to the actual item count of the first page.\",\n ),\n maxPages: z.coerce\n .number()\n .int()\n .min(1)\n .max(200)\n .optional()\n .describe(\"Maximum pages to fetch server-side (default 50, max 200).\"),\n })\n .optional();\n\nexport default defineAction({\n description:\n \"Make an arbitrary authenticated HTTP request to a shared workspace integration, configured provider API, or custom provider registered via provider-api-register. Use this as the flexible escape hatch when Dispatch needs a provider endpoint, filter, pagination mode, payload, or API version that no canned action models. The request is constrained to the provider host, uses configured credentials automatically, blocks private/internal URLs, and redacts secrets from responses.\",\n schema: z.object({\n provider: z\n .string()\n .min(1)\n .describe(\n \"Provider id to call — built-in (e.g. slack, github, notion, hubspot, gmail, google_drive, google_calendar, granola, stripe, jira) or a custom provider id registered via provider-api-register. Use provider-api-catalog to list available providers.\",\n ),\n method: MethodSchema.default(\"GET\").describe(\"HTTP method to use.\"),\n path: z\n .string()\n .min(1)\n .describe(\n \"Provider API path such as /search.messages, /repos/org/repo/issues, /crm/v3/objects/deals/search, or a full URL on an allowed provider host. Use placeholders from provider-api-catalog when provided.\",\n ),\n query: z\n .unknown()\n .optional()\n .describe(\n \"Optional query params as a JSON object/string. Array values produce repeated query params.\",\n ),\n headers: z\n .record(z.string(), z.unknown())\n .optional()\n .describe(\n \"Optional extra headers. Unsafe hop-by-hop headers are ignored. Auth headers are injected from stored credentials.\",\n ),\n body: z\n .unknown()\n .optional()\n .describe(\n \"Optional request body. Objects/arrays are JSON encoded; strings are sent as-is.\",\n ),\n auth: z\n .enum([\"default\", \"none\"])\n .default(\"default\")\n .describe(\n \"Use default to inject configured provider auth. Use none only for public provider endpoints that intentionally require no auth.\",\n ),\n connectionId: z\n .string()\n .optional()\n .describe(\n \"Optional shared workspace connection id to use when the provider has multiple granted connections.\",\n ),\n accountId: z\n .string()\n .optional()\n .describe(\n \"Optional OAuth account id to use for OAuth-backed providers such as Gmail, Google Calendar, or Google Drive.\",\n ),\n timeoutMs: z.coerce\n .number()\n .int()\n .min(1_000)\n .max(120_000)\n .optional()\n .describe(\"Request timeout in milliseconds. Default 30000, max 120000.\"),\n maxBytes: z.coerce\n .number()\n .int()\n .min(1_000)\n .max(4 * 1024 * 1024)\n .optional()\n .describe(\n \"Maximum response bytes to read. Default 1MB, max 4MB. Ignored when saveToFile is set (allows up to 20MB).\",\n ),\n saveToFile: z\n .string()\n .optional()\n .describe(\n \"Workspace file path to save the full response body to instead of returning it in context (e.g. 'analysis/provider-response.json'). When set, returns only a compact summary {savedTo, status, bytes, preview} and allows up to 20MB response. Useful for large datasets that would overflow context.\",\n ),\n stageAs: z\n .string()\n .min(1)\n .optional()\n .describe(\n \"When set, parse the response as an array of records and write them into a staged dataset with this name. Returns a compact summary instead of the raw body. Re-staging the same name replaces the previous dataset.\",\n ),\n itemsPath: z\n .string()\n .optional()\n .describe(\n \"Dot-path to the items array in the response JSON, e.g. 'items', 'results', or 'data'. Omit for auto-detection.\",\n ),\n pagination: PaginationSchema.describe(\n \"Pagination config for server-side fetchAll when stageAs is set. Supports cursor (nextCursorPath + cursorParam or cursorBodyPath), page, and offset modes.\",\n ),\n fetchAllPages: z\n .object({\n cursorPath: z\n .string()\n .describe(\n \"Dot-path in the JSON response body where the next-page cursor lives, e.g. 'meta.next_cursor' or 'pagination.next_page_token'.\",\n ),\n cursorParam: z\n .string()\n .optional()\n .describe(\n \"Query parameter name to pass the cursor on subsequent pages, e.g. 'cursor' or 'page_token'. Use cursorBodyPath instead for APIs that put cursors in POST bodies.\",\n ),\n cursorBodyPath: z\n .string()\n .optional()\n .describe(\n \"Dot-path in the JSON request body to set to the next cursor. Use for POST-body pagination.\",\n ),\n itemsPath: z\n .string()\n .optional()\n .describe(\n \"Dot-path to the items array in each response, e.g. 'results' or 'data.items'. When omitted, the whole response body is appended per page.\",\n ),\n maxPages: z.coerce\n .number()\n .int()\n .min(1)\n .max(50)\n .optional()\n .describe(\n \"Maximum pages to fetch. Default 10, max 50. Stops early when the cursor is empty.\",\n ),\n })\n .optional()\n .describe(\n \"Enable cursor-based pagination. After each response, reads cursorPath from the JSON body and re-issues the request with cursorParam or cursorBodyPath set, accumulating items from itemsPath (or whole bodies) until cursor is empty or maxPages is reached. Combine with saveToFile to write the full dataset to a workspace file.\",\n ),\n }),\n http: false,\n audit: {\n recordInputs: false,\n target: (args) => ({\n type: \"provider-api\",\n id: String(args.provider),\n visibility: \"private\",\n }),\n summary: (args) => buildProviderApiAuditSummary(args),\n },\n run: async (args) => {\n if (args.stageAs) {\n const ctx = getCredentialContext();\n if (!ctx) {\n throw new Error(\"No authenticated context for provider API staging.\");\n }\n return stagingExecuteRequest(\n {\n provider: args.provider,\n method: args.method,\n path: args.path,\n query: args.query,\n headers: args.headers,\n body: args.body,\n auth: args.auth,\n connectionId: args.connectionId,\n accountId: args.accountId,\n timeoutMs: args.timeoutMs,\n maxBytes: args.maxBytes,\n stageAs: args.stageAs,\n itemsPath: args.itemsPath,\n pagination: args.pagination,\n },\n (reqArgs) => executeProviderApiRequest(reqArgs),\n { appId: DISPATCH_APP_ID, ownerEmail: ctx.userEmail },\n );\n }\n return executeProviderApiRequest(\n args as unknown as Parameters<typeof executeProviderApiRequest>[0],\n );\n },\n});\n"]}
1
+ {"version":3,"file":"provider-api-request.js","sourceRoot":"","sources":["../../src/actions/provider-api-request.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,8BAA8B,EAC9B,8BAA8B,GAC/B,MAAM,sDAAsD,CAAC;AAC9D,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EACL,eAAe,EACf,yBAAyB,GAC1B,MAAM,+BAA+B,CAAC;AAEvC,eAAe,8BAA8B,CAC3C,EAAE,cAAc,EAAE,yBAAyB,EAAE,EAC7C;IACE,KAAK,EAAE,eAAe;IACtB,WAAW,EACT,+dAA+d;IACje,MAAM,EAAE,8BAA8B,CACpC,CAAC;SACE,MAAM,EAAE;SACR,GAAG,CAAC,CAAC,CAAC;SACN,QAAQ,CACP,uPAAuP,CACxP,CACJ;IACD,IAAI,EAAE,KAAK;CACZ,CACF,CAAC","sourcesContent":["import {\n createProviderApiRequestAction,\n createProviderApiRequestSchema,\n} from \"@agent-native/core/provider-api/actions/provider-api\";\nimport { z } from \"zod\";\n\nimport {\n DISPATCH_APP_ID,\n executeProviderApiRequest,\n} from \"../server/lib/provider-api.js\";\n\nexport default createProviderApiRequestAction(\n { executeRequest: executeProviderApiRequest },\n {\n appId: DISPATCH_APP_ID,\n description:\n \"Make an arbitrary authenticated HTTP request to a shared workspace integration, configured provider API, or custom provider registered via provider-api-register. Use this as the flexible escape hatch when Dispatch needs a provider endpoint, filter, pagination mode, payload, or API version that no canned action models. The request is constrained to the provider host, uses configured credentials automatically, blocks private/internal URLs, and redacts secrets from responses.\",\n schema: createProviderApiRequestSchema(\n z\n .string()\n .min(1)\n .describe(\n \"Provider id to call — built-in (e.g. slack, github, notion, hubspot, gmail, google_drive, google_calendar, granola, stripe, jira) or a custom provider id registered via provider-api-register. Use provider-api-catalog to list available providers.\",\n ),\n ),\n http: false,\n },\n);\n"]}
@@ -1,4 +1,21 @@
1
- declare const _default: import("@agent-native/core").ActionDefinition<{
1
+ declare const _default: import("node_modules/@agent-native/core/dist/action.js").ActionDefinition<{
2
+ datasetId: string;
3
+ where?: {
4
+ column: string;
5
+ op: "contains" | "equals" | "exists" | "gt" | "gte" | "lt" | "lte" | "not_contains" | "not_equals" | "not_exists";
6
+ value?: unknown;
7
+ }[] | undefined;
8
+ groupBy?: string[] | undefined;
9
+ aggregate?: {
10
+ column: string;
11
+ op: "avg" | "count" | "count_distinct" | "max" | "min" | "sum";
12
+ as?: string | undefined;
13
+ }[] | undefined;
14
+ select?: string[] | undefined;
15
+ orderBy?: string | undefined;
16
+ orderDir?: "asc" | "desc" | undefined;
17
+ limit?: unknown;
18
+ } | {
2
19
  datasetId: string;
3
20
  where?: {
4
21
  column: string;
@@ -1 +1 @@
1
- {"version":3,"file":"query-staged-dataset.d.ts","sourceRoot":"","sources":["../../src/actions/query-staged-dataset.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;QAwHiB,EAAE;QAAW,IAAI;QAAa,SAAS"}
1
+ {"version":3,"file":"query-staged-dataset.d.ts","sourceRoot":"","sources":["../../src/actions/query-staged-dataset.ts"],"names":[],"mappings":""}