@zackbart/connecta 0.35.0 → 0.36.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/CHANGELOG.md +97 -0
- package/README.md +8 -4
- package/bin/version.mjs +1 -1
- package/dist/auth/downstream-oauth.js +71 -79
- package/dist/auth/static-oauth.js +104 -26
- package/dist/connectors/api-connector.d.ts +17 -0
- package/dist/connectors/api-connector.js +3 -1
- package/dist/http/client.js +1 -1
- package/dist/http/hatch-paging.js +2 -2
- package/dist/http/paging.js +3 -89
- package/dist/http/provider.js +1 -2
- package/dist/http/services.js +1 -1
- package/dist/http/tools.js +1 -27
- package/dist/operator-ui/contract.d.ts +1 -0
- package/dist/operator-ui/generated.js +4 -4
- package/dist/program-writes.js +0 -1
- package/dist/providers/_shared/google/kit.js +29 -139
- package/dist/providers/_shared/rest/kit.js +4 -404
- package/dist/providers/_shared/sensitive-fields.js +0 -16
- package/dist/providers/breeze/api.js +2 -2
- package/dist/providers/ccb/api.js +1 -1
- package/dist/providers/cloudflare/api.js +8 -8
- package/dist/providers/cloudflare/lib/config.d.ts +2 -1
- package/dist/providers/docs/api.js +1 -1
- package/dist/providers/docs/tools.js +1 -2
- package/dist/providers/drive/api.js +2 -2
- package/dist/providers/drive/lib/hatch.js +1 -1
- package/dist/providers/drive/tools.js +1 -1
- package/dist/providers/forms/api.js +1 -1
- package/dist/providers/forms/lib/hatch.js +1 -1
- package/dist/providers/forms/tools.js +2 -3
- package/dist/providers/github/api.js +1 -1
- package/dist/providers/github/lib/discovery.js +2 -2
- package/dist/providers/gmail/api.js +1 -1
- package/dist/providers/gmail/tools.js +2 -2
- package/dist/providers/granola/api.js +155 -0
- package/dist/providers/granola/index.d.ts +10 -0
- package/dist/providers/granola/index.js +68 -0
- package/dist/providers/granola/openapi.generated.js +30 -0
- package/dist/providers/granola/safety.js +37 -0
- package/dist/providers/granola/skill.generated.js +5 -0
- package/dist/providers/granola/tools.js +2 -0
- package/dist/providers/overflow/api.js +26 -26
- package/dist/providers/planning-center/api.js +4 -4
- package/dist/providers/planning-center/lib/constants.d.ts +1 -1
- package/dist/providers/planning-center/lib/json-api.js +2 -2
- package/dist/providers/quickbooks/api.js +299 -0
- package/dist/providers/quickbooks/index.d.ts +13 -0
- package/dist/providers/quickbooks/index.js +93 -0
- package/dist/providers/quickbooks/lib/query.js +118 -0
- package/dist/providers/quickbooks/lib/writes.js +168 -0
- package/dist/providers/quickbooks/safety.js +222 -0
- package/dist/providers/quickbooks/skill.generated.js +5 -0
- package/dist/providers/quickbooks/tools.js +117 -0
- package/dist/providers/sheets/api.js +1 -1
- package/dist/providers/sheets/lib/hatch.js +2 -2
- package/dist/providers/sheets/lib/requests.js +1 -1
- package/dist/providers/sheets/tools.js +1 -2
- package/dist/providers/slides/api.js +1 -1
- package/dist/providers/slides/tools.js +2 -2
- package/dist/providers/stripe/api.js +7 -7
- package/dist/providers/tithely/api.js +2 -2
- package/dist/providers/vercel/api.js +12 -12
- package/dist/providers/vercel/index.js +1 -2
- package/dist/providers/vercel/lib/pin.js +1 -1
- package/dist/routes/mcp.js +1 -1
- package/dist/routes/oauth.js +3 -0
- package/dist/runtime/admission.js +0 -12
- package/dist/runtime/call.js +0 -4
- package/dist/skills.js +0 -1
- package/dist/storage/keys.js +2 -3
- package/dist/types.d.ts +2 -0
- package/dist/ui.d.ts +1 -1
- package/dist/ui.js +0 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/documentation/README.md +1 -0
- package/documentation/architecture.md +249 -366
- package/documentation/auth.md +56 -19
- package/documentation/code-mode.md +6 -6
- package/documentation/integrating.md +1 -1
- package/documentation/meta-tools.md +6 -3
- package/documentation/operator-tests.md +11 -2
- package/documentation/operator-ui.md +17 -5
- package/documentation/providers.md +492 -0
- package/package.json +12 -9
- package/templates/node/package.json +1 -1
- package/dist/operator-ui/agents.d.ts +0 -75
- package/dist/operator-ui/agents.js +0 -114
- package/dist/operator-ui/config-summary.js +0 -566
- package/dist/operator-ui/connection-map.js +0 -378
- package/dist/operator-ui/endpoints.js +0 -212
- package/dist/operator-ui/fix-prompts.d.ts +0 -18
- package/dist/operator-ui/fix-prompts.js +0 -79
- package/dist/operator-ui/health.js +0 -52
- package/dist/operator-ui/member-page.js +0 -97
- package/dist/operator-ui/overview.js +0 -126
- package/dist/operator-ui/setup-commands.js +0 -47
- package/dist/operator-ui/view.d.ts +0 -378
- package/dist/operator-ui/view.js +0 -631
- package/dist/providers/_shared/rest/dispatch.js +0 -21
- package/dist/providers/_shared/rest/tools.js +0 -592
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { quickbooksWrites } from "./lib/writes.js";
|
|
2
|
+
import { Effect, Schema } from "effect";
|
|
3
|
+
import { ConnectorCallError } from "../../errors.js";
|
|
4
|
+
import { Refusal } from "../../http/errors.js";
|
|
5
|
+
import { get as getTool, list } from "../../http/tools.js";
|
|
6
|
+
import { companyInfo, ENTITIES, queryRecords, REPORTS, recordReads, reportReads } from "./api.js";
|
|
7
|
+
import { CompanyShape, namedRecord, NamedRecordShape, object, ReportShape } from "./safety.js";
|
|
8
|
+
import { buildSearch, Filters, matches, reportParameters, reportProblem, REPORT_QUERY } from "./lib/query.js";
|
|
9
|
+
const Entity = Schema.Literals([
|
|
10
|
+
"customers",
|
|
11
|
+
"vendors",
|
|
12
|
+
"accounts",
|
|
13
|
+
"items",
|
|
14
|
+
"invoices",
|
|
15
|
+
"bills",
|
|
16
|
+
"payments",
|
|
17
|
+
"bill_payments",
|
|
18
|
+
]);
|
|
19
|
+
const Id = Schema.String.check(matches("^[1-9]\\d{0,30}$"));
|
|
20
|
+
const query = { minorversion: "75" };
|
|
21
|
+
const checked = (run) => Effect.try({
|
|
22
|
+
try: run,
|
|
23
|
+
catch: (error) => new Refusal({
|
|
24
|
+
error: error instanceof ConnectorCallError
|
|
25
|
+
? error
|
|
26
|
+
: new ConnectorCallError("invalid_args", "Invalid QuickBooks arguments."),
|
|
27
|
+
}),
|
|
28
|
+
});
|
|
29
|
+
export function quickbooksTools({ connection, pageSize, options, }) {
|
|
30
|
+
return [
|
|
31
|
+
...quickbooksWrites(connection, options.realmId),
|
|
32
|
+
getTool(connection, {
|
|
33
|
+
name: "get_company_info",
|
|
34
|
+
description: "Read the configured company's accounting identity without contact or tax identifiers.",
|
|
35
|
+
input: Schema.Struct({}),
|
|
36
|
+
output: CompanyShape,
|
|
37
|
+
fields: true,
|
|
38
|
+
run: () => connection
|
|
39
|
+
.send(companyInfo, { params: { id: options.realmId }, query })
|
|
40
|
+
.pipe(Effect.map(({ data }) => object(object(data)["CompanyInfo"]))),
|
|
41
|
+
}),
|
|
42
|
+
list(connection, {
|
|
43
|
+
name: "search_records",
|
|
44
|
+
description: "Search reviewed accounting records using bounded structured filters. Customer/vendor names are exact DisplayName matches; record ids and references join invoices, bills and accounting payments. No raw SQL. Inactive master records need an explicit Active filter.",
|
|
45
|
+
filters: {
|
|
46
|
+
entity: Entity.annotate({
|
|
47
|
+
description: "Accounting record family; payments are accounting records, not the Payments API.",
|
|
48
|
+
}),
|
|
49
|
+
filters: Schema.optionalKey(Filters.annotate({
|
|
50
|
+
description: "At most 8 AND filters. Master records: Id, Active, LastUpdatedTime and DisplayName (customers/vendors) or Name (accounts/items). Transactions: Id, LastUpdatedTime, TxnDate and CustomerRef or VendorRef. Invoices/bills/bill payments also DocNumber; invoices/bills also DueDate and Balance.",
|
|
51
|
+
})),
|
|
52
|
+
},
|
|
53
|
+
row: NamedRecordShape,
|
|
54
|
+
limit: {
|
|
55
|
+
default: pageSize,
|
|
56
|
+
max: 100,
|
|
57
|
+
description: "Rows per page, default 25, at most 100. A bounded extra row detects continuation.",
|
|
58
|
+
},
|
|
59
|
+
cursor: "bound",
|
|
60
|
+
cursorScope: { realmId: options.realmId, environment: options.environment },
|
|
61
|
+
page: (args, cursor) => Effect.gen(function* () {
|
|
62
|
+
const entity = ENTITIES[args.entity];
|
|
63
|
+
const start = cursor === undefined ? 1 : Number(cursor);
|
|
64
|
+
const sql = yield* checked(() => buildSearch(entity, args.filters ?? [], start, args.limit + 1));
|
|
65
|
+
const { data } = yield* connection.send(queryRecords, { query: { ...query, query: sql } }, { flags: { [entity]: true } });
|
|
66
|
+
const rows = object(object(data)["QueryResponse"])[entity];
|
|
67
|
+
const all = Array.isArray(rows) ? rows : [];
|
|
68
|
+
const more = all.length > args.limit;
|
|
69
|
+
return {
|
|
70
|
+
rows: all.slice(0, args.limit).map(namedRecord),
|
|
71
|
+
page: { hasMore: more, nextCursor: more ? String(start + args.limit) : null },
|
|
72
|
+
};
|
|
73
|
+
}),
|
|
74
|
+
}),
|
|
75
|
+
getTool(connection, {
|
|
76
|
+
name: "get_record",
|
|
77
|
+
description: "Read one reviewed accounting record by Id. SyncToken is its public version identifier; DocNumber is a separate human label. Contact details and payment credentials are withheld.",
|
|
78
|
+
input: Schema.Struct({
|
|
79
|
+
entity: Entity,
|
|
80
|
+
id: Id.annotate({ description: "Record Id from search_records, never DocNumber." }),
|
|
81
|
+
}),
|
|
82
|
+
output: NamedRecordShape,
|
|
83
|
+
fields: true,
|
|
84
|
+
run: (args) => connection
|
|
85
|
+
.sendPath({
|
|
86
|
+
method: "GET",
|
|
87
|
+
path: `/${ENTITIES[args.entity].toLowerCase()}/${args.id}`,
|
|
88
|
+
template: recordReads[args.entity].path,
|
|
89
|
+
query: [["minorversion", "75"]],
|
|
90
|
+
})
|
|
91
|
+
.pipe(Effect.map(({ data }) => namedRecord(object(data)[ENTITIES[args.entity]]))),
|
|
92
|
+
}),
|
|
93
|
+
getTool(connection, {
|
|
94
|
+
name: "get_report",
|
|
95
|
+
description: "Read Profit & Loss, Balance Sheet, Cash Flow or AR/AP aging summary. Preserve Header, Columns and nested Rows; empty amount strings mean no value, never zero. P&L/CashFlow support start_date; P&L/BalanceSheet support accounting_method. All accept end_date (aging as-of date). Reports retain vendor currency; no currency conversion.",
|
|
96
|
+
input: Schema.Struct({ report: Schema.Literals(REPORTS), ...REPORT_QUERY }),
|
|
97
|
+
output: ReportShape,
|
|
98
|
+
fields: true,
|
|
99
|
+
run: (args) => Effect.gen(function* () {
|
|
100
|
+
const { report, ...raw } = args;
|
|
101
|
+
const parameters = reportParameters(report, Object.fromEntries(Object.entries(raw).filter(([, value]) => value !== undefined)));
|
|
102
|
+
yield* checked(() => {
|
|
103
|
+
const problem = reportProblem(report, parameters);
|
|
104
|
+
if (problem)
|
|
105
|
+
throw new ConnectorCallError("invalid_args", problem);
|
|
106
|
+
});
|
|
107
|
+
const { data } = yield* connection.sendPath({
|
|
108
|
+
method: "GET",
|
|
109
|
+
path: `/reports/${report}`,
|
|
110
|
+
template: reportReads[report].path,
|
|
111
|
+
query: Object.entries({ ...parameters, minorversion: "75" }),
|
|
112
|
+
});
|
|
113
|
+
return object(data);
|
|
114
|
+
}),
|
|
115
|
+
}),
|
|
116
|
+
];
|
|
117
|
+
}
|
|
@@ -15,7 +15,7 @@ export const SHEETS = {
|
|
|
15
15
|
};
|
|
16
16
|
const SpreadsheetId = { spreadsheetId: Schema.String };
|
|
17
17
|
const optionalString = Schema.optionalKey(Schema.String);
|
|
18
|
-
|
|
18
|
+
const getSpreadsheet = get("getSpreadsheet", "/spreadsheets/:spreadsheetId", {
|
|
19
19
|
params: SpreadsheetId,
|
|
20
20
|
query: { includeGridData: optionalString, fields: optionalString },
|
|
21
21
|
success: Schema.Unknown,
|
|
@@ -23,7 +23,7 @@ export const sheetsIndex = new OperationIndex(sheetsDiscovery, {
|
|
|
23
23
|
pathMatching: "uri-template",
|
|
24
24
|
});
|
|
25
25
|
/** Decode range colons only. Encoded actions, ids and unreserved bytes still fail the shared backstop. */
|
|
26
|
-
|
|
26
|
+
function sheetsPath(path) {
|
|
27
27
|
const match = /^(\/spreadsheets\/[A-Za-z0-9_-]+\/values\/)([^/?#]+)$/.exec(path);
|
|
28
28
|
if (!match)
|
|
29
29
|
return path;
|
|
@@ -37,7 +37,7 @@ export function sheetsPath(path) {
|
|
|
37
37
|
}
|
|
38
38
|
const record = (value) => value !== null && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
39
39
|
/** Same scalar, range and write-cell ceilings as the named workflows, including filter-selected writes. */
|
|
40
|
-
|
|
40
|
+
function sheetsRequestProblem(call) {
|
|
41
41
|
const body = record(call.body);
|
|
42
42
|
if (call.op.path === "/spreadsheets/{spreadsheetId}:batchUpdate") {
|
|
43
43
|
const requests = body["requests"];
|
|
@@ -5,7 +5,6 @@ import { Refusal } from "../../http/errors.js";
|
|
|
5
5
|
import { googleClient, googleFailureMessage, googleOutcomeOf } from "../_shared/google/kit.js";
|
|
6
6
|
import { clampText, jsonBytes, RESULT_BUDGET_BYTES } from "../_shared/google/result-size.js";
|
|
7
7
|
import { encodeForAgent, redactBeforeCut } from "../../sent-secrets.js";
|
|
8
|
-
import { SHEETS } from "./api.js";
|
|
9
8
|
import { read, write } from "../../http/tools.js";
|
|
10
9
|
import { boundCursor } from "../../http/paging.js";
|
|
11
10
|
import { fieldsInput, fieldsProblem, selectFields } from "../../http/fields.js";
|
|
@@ -336,7 +335,7 @@ const SPREADSHEET_FIELDS = [
|
|
|
336
335
|
].join(",");
|
|
337
336
|
// --- Tools ------------------------------------------------------------------------
|
|
338
337
|
export function sheetsTools({ connection }) {
|
|
339
|
-
const client = googleClient(connection,
|
|
338
|
+
const client = googleClient(connection, sheetsIndex);
|
|
340
339
|
const readOnly = { readOnlyHint: true };
|
|
341
340
|
// Additive: nothing that existed is lost. Writes require a writable
|
|
342
341
|
// endpoint: call_destructive_tool or a program. The host controls approval.
|
|
@@ -23,7 +23,7 @@ const ReadQuery = {
|
|
|
23
23
|
commentsViewMode: Schema.optionalKey(Schema.String),
|
|
24
24
|
};
|
|
25
25
|
// Discovery calls this one parameter `presentationsId` (plural).
|
|
26
|
-
|
|
26
|
+
const getPresentation = get("getPresentation", "/presentations/:presentationsId", {
|
|
27
27
|
params: { presentationsId: Schema.String },
|
|
28
28
|
query: ReadQuery,
|
|
29
29
|
success: Schema.Unknown,
|
|
@@ -5,7 +5,7 @@ import { RESULT_BUDGET_BYTES, clampRedactedText, clampText, jsonBytes } from "..
|
|
|
5
5
|
import { googleClient, googleOutcomeOf, googleFailureMessage } from "../_shared/google/kit.js";
|
|
6
6
|
import { encodeForAgent, redactBeforeCut, redactSentSecrets } from "../../sent-secrets.js";
|
|
7
7
|
import { REQUEST_KINDS, COMMENT_KINDS, COMMENTS_UNSAVED } from "./lib/requests.js";
|
|
8
|
-
import {
|
|
8
|
+
import { SLIDES_INDEX } from "./api.js";
|
|
9
9
|
import * as contracts from "./lib/schemas.js";
|
|
10
10
|
import { read, write } from "../../http/tools.js";
|
|
11
11
|
import { Operation } from "../../runtime/call.js";
|
|
@@ -1228,7 +1228,7 @@ function postToThread(connection, client, ctx, tool, args, post) {
|
|
|
1228
1228
|
});
|
|
1229
1229
|
}
|
|
1230
1230
|
export function slidesTools({ connection }) {
|
|
1231
|
-
const client = googleClient(connection,
|
|
1231
|
+
const client = googleClient(connection, SLIDES_INDEX);
|
|
1232
1232
|
const readOnly = { readOnlyHint: true };
|
|
1233
1233
|
const presentationPath = (id) => `/presentations/${encodeURIComponent(id)}`;
|
|
1234
1234
|
const nextPage = (cursor) => cursor === null ? { hasMore: false } : { hasMore: true, nextCursor: cursor };
|
|
@@ -115,7 +115,7 @@ export const READ_CAP_MS = 60_000;
|
|
|
115
115
|
* /v1/tax/calculations` is deliberately absent: it persists a Calculation
|
|
116
116
|
* object a later Tax Transaction can reference, and Stripe bills each call.
|
|
117
117
|
*/
|
|
118
|
-
|
|
118
|
+
const READ_POSTS = [
|
|
119
119
|
["POST", "/v1/invoices/create_preview", "Computes an upcoming invoice; Stripe persists nothing."],
|
|
120
120
|
];
|
|
121
121
|
function invalid(message) {
|
|
@@ -126,7 +126,7 @@ function invalid(message) {
|
|
|
126
126
|
* The key's own prefix carries its mode, so a live key in a sandbox
|
|
127
127
|
* connector (or the reverse) is refused before any request leaves.
|
|
128
128
|
*/
|
|
129
|
-
|
|
129
|
+
function stripeKeyProblem(key, mode) {
|
|
130
130
|
if (/^(?:sk|rk)_org_/.test(key)) {
|
|
131
131
|
return "This is a Stripe organization key, which needs a Stripe-Context header this connector does not send. Use one account's secret or restricted key.";
|
|
132
132
|
}
|
|
@@ -213,7 +213,7 @@ function expansions(call) {
|
|
|
213
213
|
* secret's value, or a full Issuing card number or CVC, which an Issuing
|
|
214
214
|
* authorization, transaction, or token can embed as well as the card itself.
|
|
215
215
|
*/
|
|
216
|
-
|
|
216
|
+
function refuse(call) {
|
|
217
217
|
const expanded = expansions(call);
|
|
218
218
|
if (/^\/v1\/apps\/secrets(?:\/|$)/.test(call.path) && expanded.some((path) => /(?:^|\.)payload$/.test(path))) {
|
|
219
219
|
return "Stripe Apps secret values are not returned through Connecta. Read the secret's metadata without expanding payload.";
|
|
@@ -225,7 +225,7 @@ export function refuse(call) {
|
|
|
225
225
|
return undefined;
|
|
226
226
|
}
|
|
227
227
|
export const stripeIndex = new OperationIndex(openapi, { vendor: "stripe", title: "Stripe" });
|
|
228
|
-
|
|
228
|
+
const stripeSafety = valueSafety(STRIPE_VALUE_SAFETY, () => stripeIndex);
|
|
229
229
|
function operationRefusal(op) {
|
|
230
230
|
return (checkServer(op.server) ??
|
|
231
231
|
stripeSafety.refusal(op.method, op.path) ??
|
|
@@ -268,11 +268,11 @@ export const safety = () => ({
|
|
|
268
268
|
reviewed: restSafety(stripeSafety, stripeIndex),
|
|
269
269
|
sensitiveFields: { names: [], choice: "drop" },
|
|
270
270
|
});
|
|
271
|
-
|
|
271
|
+
const getAccount = get("getAccount", "/v1/account", {
|
|
272
272
|
headers: Schema.Struct({ "Stripe-Account": Schema.optionalKey(Schema.String) }),
|
|
273
273
|
success: Schema.Unknown,
|
|
274
274
|
});
|
|
275
|
-
|
|
275
|
+
const getBalance = get("getBalance", "/v1/balance", { success: Schema.Unknown });
|
|
276
276
|
const RESPONSE_MEDIA = { "GET /v1/quotes/{quote}/pdf": ["application/pdf"] };
|
|
277
277
|
export const StripeApi = {
|
|
278
278
|
...indexedVendor("stripe", stripeIndex, [getAccount, getBalance]),
|
|
@@ -317,7 +317,7 @@ export function connectedAccount(options) {
|
|
|
317
317
|
throw new Error('stripe() connectedAccount must be a Stripe account id ("acct_...").');
|
|
318
318
|
return account;
|
|
319
319
|
}
|
|
320
|
-
|
|
320
|
+
function checkServer(server) {
|
|
321
321
|
if (server === undefined || server === FILES_ORIGIN)
|
|
322
322
|
return undefined;
|
|
323
323
|
return server === METER_EVENTS_ORIGIN
|
|
@@ -162,7 +162,7 @@ export const listOrganizations = get("listOrganizations", "/organizations-list",
|
|
|
162
162
|
query: PageQuery,
|
|
163
163
|
success: Rows(OrganizationRecord),
|
|
164
164
|
}).annotate(Summary, "List all organizations these keys manage");
|
|
165
|
-
|
|
165
|
+
const getOrganization = get("getOrganization", "/organizations/:organization_id", {
|
|
166
166
|
params: id("organization_id"),
|
|
167
167
|
success: Single("organization_id", OrganizationRecord),
|
|
168
168
|
}).annotate(Summary, "Retrieve an organization");
|
|
@@ -174,7 +174,7 @@ export const listAllAccounts = get("listAllAccounts", "/accounts-list-all", {
|
|
|
174
174
|
query: PageQuery,
|
|
175
175
|
success: Rows(AccountRecord),
|
|
176
176
|
}).annotate(Summary, "List all donor accounts");
|
|
177
|
-
|
|
177
|
+
const getAccount = get("getAccount", "/accounts/:account_id", {
|
|
178
178
|
params: id("account_id"),
|
|
179
179
|
success: Single("account_id", AccountRecord),
|
|
180
180
|
}).annotate(Summary, "Retrieve a donor account");
|
|
@@ -17,7 +17,7 @@ import { pinAdmission, pinOptions, pinQuery, pinRoute, readPinnedTeam } from "./
|
|
|
17
17
|
export const MAX_RESPONSE_BYTES = 8 * 1024 * 1024;
|
|
18
18
|
export const READ_CAP_MS = 60_000;
|
|
19
19
|
/** POSTs that only read, admitted by `vercel_api_read`. */
|
|
20
|
-
|
|
20
|
+
const READ_POSTS = [
|
|
21
21
|
["POST", "/v2/observability/query", "Runs an Observability metrics query; Vercel persists nothing."],
|
|
22
22
|
["POST", "/v1/registrar/domains/availability", "Checks availability for a list of domains; buys nothing."],
|
|
23
23
|
["POST", "/v1/registrar/domains/price", "Quotes registrar prices for a list of domains; buys nothing."],
|
|
@@ -39,7 +39,7 @@ export function invalid(message) {
|
|
|
39
39
|
export function compact(value) {
|
|
40
40
|
return Object.fromEntries(Object.entries(value).filter(([, entry]) => entry !== undefined));
|
|
41
41
|
}
|
|
42
|
-
|
|
42
|
+
function truthy(value) {
|
|
43
43
|
return value === true || value === 1 || (typeof value === "string" && /^(?:1|true)$/i.test(value.trim()));
|
|
44
44
|
}
|
|
45
45
|
/**
|
|
@@ -155,34 +155,34 @@ class VercelIndex extends OperationIndex {
|
|
|
155
155
|
}
|
|
156
156
|
}
|
|
157
157
|
export const vercelIndex = new VercelIndex(discoveryIndex(openapi), { vendor: "vercel", title: "Vercel" });
|
|
158
|
-
|
|
158
|
+
const vercelSafety = valueSafety(VERCEL_VALUE_SAFETY, () => vercelIndex);
|
|
159
159
|
const Query = Schema.Record(Schema.String, Schema.Union([Schema.String, Schema.Array(Schema.String)]));
|
|
160
160
|
const params = (...names) => Schema.Struct(Object.fromEntries(names.map((name) => [name, Schema.String])));
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
161
|
+
const currentUser = get("currentUser", "/v2/user", { success: Schema.Unknown });
|
|
162
|
+
const teams = get("teams", "/v2/teams", { query: Query, success: Schema.Unknown });
|
|
163
|
+
const projectEnv = get("projectEnv", "/v10/projects/:idOrName/env", {
|
|
164
164
|
params: params("idOrName"),
|
|
165
165
|
query: Query,
|
|
166
166
|
success: Schema.Unknown,
|
|
167
167
|
});
|
|
168
|
-
|
|
168
|
+
const upsertEnv = post("upsertEnv", "/v10/projects/:idOrName/env", {
|
|
169
169
|
params: params("idOrName"),
|
|
170
170
|
query: Query,
|
|
171
171
|
payload: Schema.Unknown,
|
|
172
172
|
success: Schema.Unknown,
|
|
173
173
|
});
|
|
174
|
-
|
|
174
|
+
const updateEnv = patch("updateEnv", "/v9/projects/:idOrName/env/:id", {
|
|
175
175
|
params: params("idOrName", "id"),
|
|
176
176
|
query: Query,
|
|
177
177
|
payload: Schema.Unknown,
|
|
178
178
|
success: Schema.Unknown,
|
|
179
179
|
});
|
|
180
|
-
|
|
180
|
+
const buildLogs = get("buildLogs", "/v3/deployments/:idOrUrl/events", {
|
|
181
181
|
params: params("idOrUrl"),
|
|
182
182
|
query: Query,
|
|
183
183
|
success: Schema.Unknown,
|
|
184
184
|
});
|
|
185
|
-
|
|
185
|
+
const runtimeLogs = get("runtimeLogs", "/v1/projects/:projectId/deployments/:deploymentId/runtime-logs", {
|
|
186
186
|
params: params("projectId", "deploymentId"),
|
|
187
187
|
query: Query,
|
|
188
188
|
success: Schema.Unknown,
|
|
@@ -294,7 +294,7 @@ export const refuse = (call) => {
|
|
|
294
294
|
}
|
|
295
295
|
return undefined;
|
|
296
296
|
};
|
|
297
|
-
|
|
297
|
+
function scope(call, teamId, pin) {
|
|
298
298
|
if (pin)
|
|
299
299
|
return { ...call, query: pinQuery(vercelIndex, call, pin) };
|
|
300
300
|
const query = { ...call.query };
|
|
@@ -374,7 +374,7 @@ export function queryOf(call) {
|
|
|
374
374
|
export function queryPairs(call) {
|
|
375
375
|
return Object.entries(queryOf(call)).flatMap(([key, value]) => (Array.isArray(value) ? value : [value]).map((value) => [key, value]));
|
|
376
376
|
}
|
|
377
|
-
|
|
377
|
+
function sendVercel(connection, call, options, sendOptions) {
|
|
378
378
|
return checked(() => {
|
|
379
379
|
const server = checkServer(call.op.server);
|
|
380
380
|
if (server)
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { keys, optionsOf, variants } from "../../config-schema.js";
|
|
2
2
|
import { defineApiProvider } from "../../http/provider.js";
|
|
3
3
|
import { CALL_ADMISSION } from "../../provider.js";
|
|
4
|
-
import { removedHostedMcp } from "../_shared/rest/dispatch.js";
|
|
5
4
|
import { authenticate, MAX_RESPONSE_BYTES, READ_CAP_MS, probe, result, safety, vercelErrors, VercelApi, usageGuide, transformGuide, VERCEL_VERDICTS, VERCEL_PAGES, vercelBinding, vercelIndex, } from "./api.js";
|
|
6
5
|
import { VERCEL_API_BASE_URL } from "./lib/config.js";
|
|
7
6
|
import { pinOptions, PIN_WRITE_STEPS } from "./lib/pin.js";
|
|
@@ -38,7 +37,7 @@ export const vercel = defineApiProvider({
|
|
|
38
37
|
vendor: VercelApi,
|
|
39
38
|
baseUrl: (options) => {
|
|
40
39
|
if (options.auth.type !== "token")
|
|
41
|
-
|
|
40
|
+
throw new Error("remoteMcp() with ConnectaConfig.classification for hosted MCP connections; use a distinct id beside the API connector.");
|
|
42
41
|
pinOptions(options);
|
|
43
42
|
return options.baseUrl ?? VERCEL_API_BASE_URL;
|
|
44
43
|
},
|
|
@@ -34,7 +34,7 @@ const object = (value) => value !== null && typeof value === "object" && !Array.
|
|
|
34
34
|
const fail = (reason) => {
|
|
35
35
|
throw new ConnectorCallError("provider_permission_denied", `Vercel team pin: ${reason} Not sent to the requested resource.`, { retryable: false });
|
|
36
36
|
};
|
|
37
|
-
|
|
37
|
+
function validatePin(options) {
|
|
38
38
|
if (options.pin === undefined)
|
|
39
39
|
return;
|
|
40
40
|
const id = options.pin?.teamId;
|
package/dist/routes/mcp.js
CHANGED
|
@@ -268,7 +268,7 @@ function scopedToBody(handler, signal) {
|
|
|
268
268
|
* The request's admission permit, owned by its Scope.
|
|
269
269
|
*
|
|
270
270
|
* Admission goes through the controller's Promise rather than its Effect
|
|
271
|
-
* program
|
|
271
|
+
* program, on purpose. The pool is shared by every request
|
|
272
272
|
* in the isolate, and a queued request is handed its permit from inside the
|
|
273
273
|
* request whose body just ended. A fiber resumed there would authorize and
|
|
274
274
|
* serve this request in that one's I/O context, which workerd refuses;
|
package/dist/routes/oauth.js
CHANGED
|
@@ -217,6 +217,9 @@ async function finishOAuthCallback(context) {
|
|
|
217
217
|
if (["state", "iss", "code", "error"].some((name) => url.searchParams.getAll(name).length > 1))
|
|
218
218
|
return refused();
|
|
219
219
|
try {
|
|
220
|
+
if (connector.verifyCallbackParameters &&
|
|
221
|
+
!(await connector.verifyCallbackParameters(url.searchParams, connectorContext)))
|
|
222
|
+
return refused();
|
|
220
223
|
const issuer = url.searchParams.get("iss");
|
|
221
224
|
if (connector.verifyCallbackIssuer) {
|
|
222
225
|
if (!(await connector.verifyCallbackIssuer(issuer, connectorContext)))
|
|
@@ -7,7 +7,6 @@
|
|
|
7
7
|
// read its private bookkeeping, and one that emits nothing into the `.d.ts`.
|
|
8
8
|
// Promise callers keep `acquire()`, which runs the same program through
|
|
9
9
|
// runEdge; Effect callers come through this module and never see a Promise.
|
|
10
|
-
import { Effect } from "effect";
|
|
11
10
|
let program;
|
|
12
11
|
/**
|
|
13
12
|
* Install the controller's admission program. Called once, by
|
|
@@ -32,14 +31,3 @@ export function admit(controller, options = {}) {
|
|
|
32
31
|
}
|
|
33
32
|
return program(controller, options.signal, options.wait !== false);
|
|
34
33
|
}
|
|
35
|
-
/**
|
|
36
|
-
* A lease owned by the enclosing Scope: released when the scope closes, on
|
|
37
|
-
* success, failure, or interruption alike. The wait itself stays
|
|
38
|
-
* interruptible — a queued request whose caller left must not hold its place
|
|
39
|
-
* in line until the queue timeout.
|
|
40
|
-
*/
|
|
41
|
-
export function acquireScoped(controller, options = {}) {
|
|
42
|
-
return Effect.acquireRelease(admit(controller, options), (lease) => Effect.sync(() => lease.release()), {
|
|
43
|
-
interruptible: true,
|
|
44
|
-
});
|
|
45
|
-
}
|
package/dist/runtime/call.js
CHANGED
|
@@ -292,9 +292,6 @@ export function deriveView(view, overrides) {
|
|
|
292
292
|
views.set(derived, entry);
|
|
293
293
|
return derived;
|
|
294
294
|
}
|
|
295
|
-
export function viewCaller(view) {
|
|
296
|
-
return serviceFor(view, Caller);
|
|
297
|
-
}
|
|
298
295
|
export function viewLease(view) {
|
|
299
296
|
return views.get(view)?.call;
|
|
300
297
|
}
|
|
@@ -337,7 +334,6 @@ export function contextView(lease, operation) {
|
|
|
337
334
|
lease.close();
|
|
338
335
|
return view;
|
|
339
336
|
}
|
|
340
|
-
export const callView = (operation, lease) => contextView(lease, operation);
|
|
341
337
|
export function chargeView(view) {
|
|
342
338
|
const budget = recordedService(view, Budget);
|
|
343
339
|
return budget ? runEdge(budget.charge) : Promise.reject(ended());
|
package/dist/skills.js
CHANGED
|
@@ -32,7 +32,6 @@ export function endpointInstructions(description, native) {
|
|
|
32
32
|
export function nativeInstructions(executeCode) {
|
|
33
33
|
return `Each tool here is one operation; annotations classify reads/writes. Call known tools directly; ${executeCode ? "combine work in execute_code using the program addresses in tool descriptions." : "find tools with your host's search."} Read-only endpoints omit and refuse writes. Never repeat a write for output. Give auth handoffs to the user/operator. Follow nextAction to page with ${executeCode ? "connecta.result in execute_code" : "read_result"}. skills lists guidance.`;
|
|
34
34
|
}
|
|
35
|
-
export { USAGE_SKILL } from "./usage-guide.js";
|
|
36
35
|
/** True when at least one of `connectors` carries a usage guide. */
|
|
37
36
|
export function hasConnectorGuides(connectors) {
|
|
38
37
|
return connectors.some((connector) => connectorGuide(connector) !== undefined);
|
package/dist/storage/keys.js
CHANGED
|
@@ -2,9 +2,8 @@
|
|
|
2
2
|
//
|
|
3
3
|
// A deployment has one KVStorage (D1 on Workers, SQLite on Node, memory in
|
|
4
4
|
// tests), and every subsystem shares it. Sharing is safe because no two
|
|
5
|
-
// families claim overlapping keys
|
|
6
|
-
//
|
|
7
|
-
// spells one of these prefixes itself.
|
|
5
|
+
// families claim overlapping keys. Build every key here; persistence journeys
|
|
6
|
+
// check actual isolation through the deployment and its physical database.
|
|
8
7
|
//
|
|
9
8
|
// Each family records:
|
|
10
9
|
//
|
package/dist/types.d.ts
CHANGED
|
@@ -432,6 +432,8 @@ export interface Connector {
|
|
|
432
432
|
* pending URL could complete consent with their own account.
|
|
433
433
|
*/
|
|
434
434
|
verifyState?(state: string | null, ctx: ConnectorContext): Promise<boolean>;
|
|
435
|
+
/** Validate provider callback parameters after state verification and before issuer validation, including errors. */
|
|
436
|
+
verifyCallbackParameters?(params: URLSearchParams, ctx: ConnectorContext): Promise<boolean>;
|
|
435
437
|
/** Validate a callback issuer against its verified consent, including error responses. */
|
|
436
438
|
verifyCallbackIssuer?(issuer: string | null, ctx: ConnectorContext): Promise<boolean>;
|
|
437
439
|
/**
|
package/dist/ui.d.ts
CHANGED
|
@@ -6,7 +6,7 @@ import type { RegistryView } from "./registry.js";
|
|
|
6
6
|
import type { ConnectaBranding, Connector, ConnectorStatus, ToolDef, UiAuthConfig } from "./types.js";
|
|
7
7
|
export { filterUiConnectors, type CredentialManagementCapability, type UiConnector, type UiData, } from "./operator-ui/model.js";
|
|
8
8
|
export { CONNECTA_FAVICON_SVG, resolveBranding, isSafeHttpUrl, isSafeHttpsUrl, isSafeIconHref } from "./branding.js";
|
|
9
|
-
export type OperatorPage = import("./operator-ui/
|
|
9
|
+
export type OperatorPage = import("./operator-ui/contract.js").OperatorPage;
|
|
10
10
|
export declare function operatorPageForPath(path: string): OperatorPage | undefined;
|
|
11
11
|
export declare function operatorPageTitle(page: OperatorPage, configuredTitle: string): string;
|
|
12
12
|
/** Report the verdict the registry stored, independent of whether an endpoint is read-only. */
|
package/dist/ui.js
CHANGED
|
@@ -164,7 +164,6 @@ _nonce, page = "endpoints") {
|
|
|
164
164
|
productName: brand.productName,
|
|
165
165
|
brandMark: brandMark(branding, true),
|
|
166
166
|
productDescription: brand.description,
|
|
167
|
-
productOperatorLabel: brand.productName + " operator",
|
|
168
167
|
})}</script><script defer src="${OPERATOR_UI_SCRIPT_PATH}"></script>`,
|
|
169
168
|
});
|
|
170
169
|
}
|
package/dist/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const CONNECTA_VERSION = "0.
|
|
1
|
+
export declare const CONNECTA_VERSION = "0.36.1";
|
package/dist/version.js
CHANGED
package/documentation/README.md
CHANGED
|
@@ -12,6 +12,7 @@ For a new deployment, start with [Deploying Connecta](./deploying.md).
|
|
|
12
12
|
| ---------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
|
|
13
13
|
| Add or remove a connector | [Change the connector roster](./integrating.md#add-or-remove-a-connector) |
|
|
14
14
|
| Set up a maintained provider | [Maintained provider setup](./providers.md) |
|
|
15
|
+
| Inspect maintained API sources and tools | [API sources and tool inventory](./providers.md#api-sources-and-tool-inventory) |
|
|
15
16
|
| Organize an agent's pools and tiers | [Organizing an agent's pools](./auth.md#organizing-an-agents-pools) |
|
|
16
17
|
| Add a person (maintainer or pool member) | [Add a person](./auth.md#add-a-person), [member page](./operator-ui.md#use-the-member-page) |
|
|
17
18
|
| Connect a shared credential | [Connect a shared credential](./auth.md#connect-a-shared-credential) |
|