@vornrun/connector-sdk 0.7.0 → 0.7.1-beta.2
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 +2 -0
- package/dist/{check-62s2GvcO.d.ts → check-CzSTEQD8.d.ts} +2 -0
- package/dist/{chunk-ZKHXHE3O.js → chunk-C2WRZCMZ.js} +112 -87
- package/dist/cli.d.ts +1 -1
- package/dist/cli.js +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -217,6 +217,8 @@ auth: {
|
|
|
217
217
|
}
|
|
218
218
|
```
|
|
219
219
|
|
|
220
|
+
Add `headers` to `check` for a site whose reads need one, such as a CSRF flag. Headers the browser sets itself or that carry who you are, such as `cookie`, `authorization`, `origin` or any `sec-` header, are refused.
|
|
221
|
+
|
|
220
222
|
Vorn opens a window on a browser profile that belongs to one connection, and the person signs in there. The connector's code then gets `ctx.session.fetch` beside `ctx.fetch`. A call through `ctx.session.fetch` runs inside that signed-in window as a same-origin request, so the service sees its own page asking and no cookie reaches the connector. Calls outside `origins` are refused. `ctx.fetch` stays a plain fetch for public reads, such as a feed, which work before anyone signs in. A `browser` connector's declared `request` actions go through the window.
|
|
221
223
|
|
|
222
224
|
`--mock` serves signed-in calls from the same routes as every other call. A `--live` run from a terminal has no window, so it skips them.
|
|
@@ -389,6 +389,8 @@ interface BrowserSignIn {
|
|
|
389
389
|
check: {
|
|
390
390
|
url: string;
|
|
391
391
|
identity: string[];
|
|
392
|
+
/** Sent with the check, for a site whose reads need a header such as a CSRF flag. */
|
|
393
|
+
headers?: Record<string, string>;
|
|
392
394
|
};
|
|
393
395
|
}
|
|
394
396
|
/** The signed-in window, offered to a `browser` connector's code. */
|
|
@@ -122,6 +122,101 @@ function withinOrigins(origins, url) {
|
|
|
122
122
|
return wildcard ? target.endsWith(`.${host}`) : target === host;
|
|
123
123
|
});
|
|
124
124
|
}
|
|
125
|
+
var FORBIDDEN_SESSION_HEADERS = /* @__PURE__ */ new Set([
|
|
126
|
+
"cookie",
|
|
127
|
+
"cookie2",
|
|
128
|
+
"authorization",
|
|
129
|
+
"host",
|
|
130
|
+
"origin",
|
|
131
|
+
"referer",
|
|
132
|
+
"content-length"
|
|
133
|
+
]);
|
|
134
|
+
var HEADER_NAME = /^[A-Za-z0-9!#$%&'*+.^_`|~-]+$/;
|
|
135
|
+
function allowedSessionHeader(name) {
|
|
136
|
+
const lower = name.toLowerCase();
|
|
137
|
+
return HEADER_NAME.test(name) && !FORBIDDEN_SESSION_HEADERS.has(lower) && !lower.startsWith("sec-") && !lower.startsWith("proxy-");
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// src/post-receive.ts
|
|
141
|
+
var UNSAFE_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
|
|
142
|
+
function isRecord(value) {
|
|
143
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
144
|
+
}
|
|
145
|
+
function segments(path) {
|
|
146
|
+
return path.split(".").map((part) => part.trim()).filter((part) => part !== "");
|
|
147
|
+
}
|
|
148
|
+
function valueAt(value, path) {
|
|
149
|
+
let current = value;
|
|
150
|
+
for (const key of segments(path)) {
|
|
151
|
+
if (UNSAFE_KEYS.has(key)) return void 0;
|
|
152
|
+
if (Array.isArray(current)) {
|
|
153
|
+
const index = Number(key);
|
|
154
|
+
if (!Number.isInteger(index)) return void 0;
|
|
155
|
+
current = current[index];
|
|
156
|
+
continue;
|
|
157
|
+
}
|
|
158
|
+
if (!isRecord(current)) return void 0;
|
|
159
|
+
current = Object.prototype.hasOwnProperty.call(current, key) ? current[key] : void 0;
|
|
160
|
+
}
|
|
161
|
+
return current;
|
|
162
|
+
}
|
|
163
|
+
function withValueAt(value, path, next) {
|
|
164
|
+
const keys = segments(path);
|
|
165
|
+
if (keys.length === 0) return next;
|
|
166
|
+
const [head, ...rest] = keys;
|
|
167
|
+
if (UNSAFE_KEYS.has(head)) return value;
|
|
168
|
+
if (Array.isArray(value)) {
|
|
169
|
+
const index = Number(head);
|
|
170
|
+
if (!Number.isInteger(index)) return value;
|
|
171
|
+
const copy = [...value];
|
|
172
|
+
copy[index] = rest.length === 0 ? next : withValueAt(copy[index], rest.join("."), next);
|
|
173
|
+
return copy;
|
|
174
|
+
}
|
|
175
|
+
const base = isRecord(value) ? value : {};
|
|
176
|
+
return {
|
|
177
|
+
...base,
|
|
178
|
+
[head]: rest.length === 0 ? next : withValueAt(base[head], rest.join("."), next)
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
function pick(value, keys) {
|
|
182
|
+
if (Array.isArray(value)) return value.map((entry) => pick(entry, keys));
|
|
183
|
+
if (!isRecord(value)) return value;
|
|
184
|
+
const out = {};
|
|
185
|
+
for (const key of keys) {
|
|
186
|
+
if (UNSAFE_KEYS.has(key)) continue;
|
|
187
|
+
if (Object.prototype.hasOwnProperty.call(value, key)) out[key] = value[key];
|
|
188
|
+
}
|
|
189
|
+
return out;
|
|
190
|
+
}
|
|
191
|
+
function rename(value, from, to) {
|
|
192
|
+
if (Array.isArray(value)) return value.map((entry) => rename(entry, from, to));
|
|
193
|
+
if (!isRecord(value)) return value;
|
|
194
|
+
if (UNSAFE_KEYS.has(from) || UNSAFE_KEYS.has(to)) return value;
|
|
195
|
+
if (!Object.prototype.hasOwnProperty.call(value, from)) return value;
|
|
196
|
+
const out = {};
|
|
197
|
+
for (const [key, entry] of Object.entries(value)) {
|
|
198
|
+
if (key === from) out[to] = entry;
|
|
199
|
+
else if (key !== to) out[key] = entry;
|
|
200
|
+
}
|
|
201
|
+
return out;
|
|
202
|
+
}
|
|
203
|
+
function applyOp(value, op) {
|
|
204
|
+
if (op.op === "flatten") return valueAt(value, op.path);
|
|
205
|
+
const target = op.path === void 0 ? value : valueAt(value, op.path);
|
|
206
|
+
if (op.path !== void 0 && target === void 0) return value;
|
|
207
|
+
let next;
|
|
208
|
+
if (op.op === "pick") next = pick(target, op.keys);
|
|
209
|
+
else if (op.op === "rename") next = rename(target, op.from, op.to);
|
|
210
|
+
else if (op.op === "filter") {
|
|
211
|
+
next = Array.isArray(target) ? target.filter((entry) => isRecord(entry) && valueAt(entry, op.key) === op.equals) : target;
|
|
212
|
+
} else {
|
|
213
|
+
next = Array.isArray(target) ? target.map((entry) => applyPostReceive(entry, op.ops)) : target;
|
|
214
|
+
}
|
|
215
|
+
return op.path === void 0 ? next : withValueAt(value, op.path, next);
|
|
216
|
+
}
|
|
217
|
+
function applyPostReceive(value, ops) {
|
|
218
|
+
return (ops ?? []).reduce(applyOp, value);
|
|
219
|
+
}
|
|
125
220
|
|
|
126
221
|
// src/define.ts
|
|
127
222
|
var KEY_PATTERN = /^[a-zA-Z][a-zA-Z0-9_-]*$/;
|
|
@@ -270,6 +365,16 @@ function assertBrowserSignIn(id, browser) {
|
|
|
270
365
|
if (!Array.isArray(identity) || identity.some((path) => typeof path !== "string" || !path.trim())) {
|
|
271
366
|
throw new Error(`Connector ${id} must name its identity fields as non-empty strings`);
|
|
272
367
|
}
|
|
368
|
+
const headers = browser.check?.headers;
|
|
369
|
+
if (headers === void 0) return;
|
|
370
|
+
const badHeader = isRecord(headers) ? Object.entries(headers).find(
|
|
371
|
+
([name, value]) => typeof value !== "string" || !allowedSessionHeader(name)
|
|
372
|
+
) : void 0;
|
|
373
|
+
if (!isRecord(headers) || badHeader) {
|
|
374
|
+
throw new Error(
|
|
375
|
+
`Connector ${id} may add only plain string headers to its signed-in check` + (badHeader ? `; ${JSON.stringify(badHeader[0])} is not one` : "")
|
|
376
|
+
);
|
|
377
|
+
}
|
|
273
378
|
}
|
|
274
379
|
function assertIdentity(kind, definition) {
|
|
275
380
|
if (!KEY_PATTERN.test(definition.id ?? "")) {
|
|
@@ -1121,7 +1226,7 @@ var RESERVED_KEYS = [
|
|
|
1121
1226
|
"assignee",
|
|
1122
1227
|
"updatedAt"
|
|
1123
1228
|
];
|
|
1124
|
-
var
|
|
1229
|
+
var UNSAFE_KEYS2 = ["__proto__", "constructor", "prototype"];
|
|
1125
1230
|
function itemExternalId(item) {
|
|
1126
1231
|
return String(item.externalId ?? "").trim();
|
|
1127
1232
|
}
|
|
@@ -1147,7 +1252,7 @@ function normalizeItem(item, polledAt) {
|
|
|
1147
1252
|
const extra = {};
|
|
1148
1253
|
for (const [key, value] of Object.entries(item.data ?? {})) {
|
|
1149
1254
|
if (RESERVED_KEYS.includes(key)) continue;
|
|
1150
|
-
if (
|
|
1255
|
+
if (UNSAFE_KEYS2.includes(key)) continue;
|
|
1151
1256
|
extra[key] = value;
|
|
1152
1257
|
}
|
|
1153
1258
|
return {
|
|
@@ -1292,87 +1397,6 @@ async function runFetch(type, fetchItems, context) {
|
|
|
1292
1397
|
return fetched;
|
|
1293
1398
|
}
|
|
1294
1399
|
|
|
1295
|
-
// src/post-receive.ts
|
|
1296
|
-
var UNSAFE_KEYS2 = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
|
|
1297
|
-
function isRecord(value) {
|
|
1298
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1299
|
-
}
|
|
1300
|
-
function segments(path) {
|
|
1301
|
-
return path.split(".").map((part) => part.trim()).filter((part) => part !== "");
|
|
1302
|
-
}
|
|
1303
|
-
function valueAt(value, path) {
|
|
1304
|
-
let current = value;
|
|
1305
|
-
for (const key of segments(path)) {
|
|
1306
|
-
if (UNSAFE_KEYS2.has(key)) return void 0;
|
|
1307
|
-
if (Array.isArray(current)) {
|
|
1308
|
-
const index = Number(key);
|
|
1309
|
-
if (!Number.isInteger(index)) return void 0;
|
|
1310
|
-
current = current[index];
|
|
1311
|
-
continue;
|
|
1312
|
-
}
|
|
1313
|
-
if (!isRecord(current)) return void 0;
|
|
1314
|
-
current = Object.prototype.hasOwnProperty.call(current, key) ? current[key] : void 0;
|
|
1315
|
-
}
|
|
1316
|
-
return current;
|
|
1317
|
-
}
|
|
1318
|
-
function withValueAt(value, path, next) {
|
|
1319
|
-
const keys = segments(path);
|
|
1320
|
-
if (keys.length === 0) return next;
|
|
1321
|
-
const [head, ...rest] = keys;
|
|
1322
|
-
if (UNSAFE_KEYS2.has(head)) return value;
|
|
1323
|
-
if (Array.isArray(value)) {
|
|
1324
|
-
const index = Number(head);
|
|
1325
|
-
if (!Number.isInteger(index)) return value;
|
|
1326
|
-
const copy = [...value];
|
|
1327
|
-
copy[index] = rest.length === 0 ? next : withValueAt(copy[index], rest.join("."), next);
|
|
1328
|
-
return copy;
|
|
1329
|
-
}
|
|
1330
|
-
const base = isRecord(value) ? value : {};
|
|
1331
|
-
return {
|
|
1332
|
-
...base,
|
|
1333
|
-
[head]: rest.length === 0 ? next : withValueAt(base[head], rest.join("."), next)
|
|
1334
|
-
};
|
|
1335
|
-
}
|
|
1336
|
-
function pick(value, keys) {
|
|
1337
|
-
if (Array.isArray(value)) return value.map((entry) => pick(entry, keys));
|
|
1338
|
-
if (!isRecord(value)) return value;
|
|
1339
|
-
const out = {};
|
|
1340
|
-
for (const key of keys) {
|
|
1341
|
-
if (UNSAFE_KEYS2.has(key)) continue;
|
|
1342
|
-
if (Object.prototype.hasOwnProperty.call(value, key)) out[key] = value[key];
|
|
1343
|
-
}
|
|
1344
|
-
return out;
|
|
1345
|
-
}
|
|
1346
|
-
function rename(value, from, to) {
|
|
1347
|
-
if (Array.isArray(value)) return value.map((entry) => rename(entry, from, to));
|
|
1348
|
-
if (!isRecord(value)) return value;
|
|
1349
|
-
if (UNSAFE_KEYS2.has(from) || UNSAFE_KEYS2.has(to)) return value;
|
|
1350
|
-
if (!Object.prototype.hasOwnProperty.call(value, from)) return value;
|
|
1351
|
-
const out = {};
|
|
1352
|
-
for (const [key, entry] of Object.entries(value)) {
|
|
1353
|
-
if (key === from) out[to] = entry;
|
|
1354
|
-
else if (key !== to) out[key] = entry;
|
|
1355
|
-
}
|
|
1356
|
-
return out;
|
|
1357
|
-
}
|
|
1358
|
-
function applyOp(value, op) {
|
|
1359
|
-
if (op.op === "flatten") return valueAt(value, op.path);
|
|
1360
|
-
const target = op.path === void 0 ? value : valueAt(value, op.path);
|
|
1361
|
-
if (op.path !== void 0 && target === void 0) return value;
|
|
1362
|
-
let next;
|
|
1363
|
-
if (op.op === "pick") next = pick(target, op.keys);
|
|
1364
|
-
else if (op.op === "rename") next = rename(target, op.from, op.to);
|
|
1365
|
-
else if (op.op === "filter") {
|
|
1366
|
-
next = Array.isArray(target) ? target.filter((entry) => isRecord(entry) && valueAt(entry, op.key) === op.equals) : target;
|
|
1367
|
-
} else {
|
|
1368
|
-
next = Array.isArray(target) ? target.map((entry) => applyPostReceive(entry, op.ops)) : target;
|
|
1369
|
-
}
|
|
1370
|
-
return op.path === void 0 ? next : withValueAt(value, op.path, next);
|
|
1371
|
-
}
|
|
1372
|
-
function applyPostReceive(value, ops) {
|
|
1373
|
-
return (ops ?? []).reduce(applyOp, value);
|
|
1374
|
-
}
|
|
1375
|
-
|
|
1376
1400
|
// src/request.ts
|
|
1377
1401
|
var MAX_ERROR_BODY = 500;
|
|
1378
1402
|
var PLACEHOLDER = /\{\{\s*(args|config)\.([A-Za-z0-9_.-]+)\s*\}\}/g;
|
|
@@ -3227,12 +3251,13 @@ function inputShape(inputs) {
|
|
|
3227
3251
|
function scalar(type) {
|
|
3228
3252
|
if (type === "number") return z.number();
|
|
3229
3253
|
if (type === "boolean") return z.boolean();
|
|
3230
|
-
return z.string();
|
|
3254
|
+
if (type === "string") return z.string();
|
|
3255
|
+
return z.unknown();
|
|
3231
3256
|
}
|
|
3232
3257
|
function outputSchema(outputs) {
|
|
3233
3258
|
const shape = {};
|
|
3234
3259
|
for (const output of outputs) {
|
|
3235
|
-
shape[output.key] = scalar(output.type).
|
|
3260
|
+
shape[output.key] = scalar(output.type).nullish().describe(output.description ?? output.key);
|
|
3236
3261
|
}
|
|
3237
3262
|
return z.looseObject(shape);
|
|
3238
3263
|
}
|
|
@@ -3450,6 +3475,8 @@ export {
|
|
|
3450
3475
|
createSessionFetch,
|
|
3451
3476
|
ORIGIN_PATTERN,
|
|
3452
3477
|
withinOrigins,
|
|
3478
|
+
valueAt,
|
|
3479
|
+
applyPostReceive,
|
|
3453
3480
|
EXTENSION_PERMISSIONS,
|
|
3454
3481
|
HOST_PERMISSIONS,
|
|
3455
3482
|
envNameFor,
|
|
@@ -3477,8 +3504,6 @@ export {
|
|
|
3477
3504
|
normalizeItem,
|
|
3478
3505
|
normalizeItems,
|
|
3479
3506
|
pollWithDedupe,
|
|
3480
|
-
valueAt,
|
|
3481
|
-
applyPostReceive,
|
|
3482
3507
|
resolveTemplates,
|
|
3483
3508
|
resolveRequest,
|
|
3484
3509
|
asOutput,
|
package/dist/cli.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { B as BundleRequest, a as BundleOutput, C as CheckFinding } from './check-
|
|
2
|
+
import { B as BundleRequest, a as BundleOutput, C as CheckFinding } from './check-CzSTEQD8.js';
|
|
3
3
|
|
|
4
4
|
interface CliDeps {
|
|
5
5
|
load(modulePath: string): Promise<unknown>;
|
package/dist/cli.js
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { E as ExtensionPermission, b as ExtensionHostMethod, c as ConnectorDefinition, d as Connector, e as ExtensionDefinition, f as ConnectorConfig, g as ExtensionHost, T as TriggerDefinition, P as PollContext, h as PollOutcome, i as ConnectorItem, N as NormalizedItem, j as PostReceiveOp, A as ActionRequest, B as BundleRequest, a as BundleOutput, C as CheckFinding } from './check-
|
|
2
|
-
export { k as ActionContext, l as ActionDefinition, m as ActionInputField, n as ActionInputOption, o as ActionInputType, p as ActionOutputField, q as ActivationPredicate, r as AuthRung, s as BrowserSignIn, t as CHECK_OWNERS, u as CheckCode, v as CheckOptions, w as ConformanceRun, x as ConnectionSetup, y as ConnectorAuth, z as ConnectorConfigField, D as ConnectorHarness, F as ConnectorIcon, G as ConnectorKind, H as ConnectorManifest, I as ConnectorVerification, J as DedupeStrategy, K as DefaultWorkflow, L as ExtensionAgent, M as ExtensionContext, O as ExtensionContributions, Q as ExtensionPlatform, R as ExtensionUsage, S as ExtensionUsageWindow, U as FetchContext, V as FooterContribution, W as FooterItem, X as HarnessOptions, Y as LinkContext, Z as LinkHandled, _ as LinkHandlerContribution, $ as MANIFEST_TOOL, a0 as MAX_PACK_BYTES, a1 as MAX_POLL_PAGES, a2 as ManifestContributions, a3 as MockCall, a4 as MockHostAnswers, a5 as MockHostRun, a6 as MockRoute, a7 as MockRouteMissError, a8 as MockRun, a9 as OPTIONS_TOOL, aa as OptionsContext, ab as OptionsLoader, ac as PREFLIGHT_TOOL, ad as PaginationStrategy, ae as PaneContribution, af as PollPage, ag as PreflightResult, ah as ResilientFetchOptions, ai as RetryPolicy, aj as RunActionOptions, ak as RunPollOptions, al as SessionContext, am as StatusSuggestion, an as backoffMs, ao as bundleDependencyFindings, ap as bundledRequireFindings, aq as checkConnector, ar as connectionSetup, as as connectorManifest, at as createConnectorHarness, au as drainPoll, av as esbuildBundle, aw as escapedMockHttp, ax as footerToolName, ay as formatFindings, az as handlerToolName, aA as lifecycleScriptFindings, aB as mockExtensionHost, aC as pollToolName, aD as readNearestPackageJson, aE as resilientFetch, aF as retryAfterMs, aG as runAction, aH as runConformance, aI as runOptions, aJ as runPoll, aK as withMockHttp } from './check-
|
|
1
|
+
import { E as ExtensionPermission, b as ExtensionHostMethod, c as ConnectorDefinition, d as Connector, e as ExtensionDefinition, f as ConnectorConfig, g as ExtensionHost, T as TriggerDefinition, P as PollContext, h as PollOutcome, i as ConnectorItem, N as NormalizedItem, j as PostReceiveOp, A as ActionRequest, B as BundleRequest, a as BundleOutput, C as CheckFinding } from './check-CzSTEQD8.js';
|
|
2
|
+
export { k as ActionContext, l as ActionDefinition, m as ActionInputField, n as ActionInputOption, o as ActionInputType, p as ActionOutputField, q as ActivationPredicate, r as AuthRung, s as BrowserSignIn, t as CHECK_OWNERS, u as CheckCode, v as CheckOptions, w as ConformanceRun, x as ConnectionSetup, y as ConnectorAuth, z as ConnectorConfigField, D as ConnectorHarness, F as ConnectorIcon, G as ConnectorKind, H as ConnectorManifest, I as ConnectorVerification, J as DedupeStrategy, K as DefaultWorkflow, L as ExtensionAgent, M as ExtensionContext, O as ExtensionContributions, Q as ExtensionPlatform, R as ExtensionUsage, S as ExtensionUsageWindow, U as FetchContext, V as FooterContribution, W as FooterItem, X as HarnessOptions, Y as LinkContext, Z as LinkHandled, _ as LinkHandlerContribution, $ as MANIFEST_TOOL, a0 as MAX_PACK_BYTES, a1 as MAX_POLL_PAGES, a2 as ManifestContributions, a3 as MockCall, a4 as MockHostAnswers, a5 as MockHostRun, a6 as MockRoute, a7 as MockRouteMissError, a8 as MockRun, a9 as OPTIONS_TOOL, aa as OptionsContext, ab as OptionsLoader, ac as PREFLIGHT_TOOL, ad as PaginationStrategy, ae as PaneContribution, af as PollPage, ag as PreflightResult, ah as ResilientFetchOptions, ai as RetryPolicy, aj as RunActionOptions, ak as RunPollOptions, al as SessionContext, am as StatusSuggestion, an as backoffMs, ao as bundleDependencyFindings, ap as bundledRequireFindings, aq as checkConnector, ar as connectionSetup, as as connectorManifest, at as createConnectorHarness, au as drainPoll, av as esbuildBundle, aw as escapedMockHttp, ax as footerToolName, ay as formatFindings, az as handlerToolName, aA as lifecycleScriptFindings, aB as mockExtensionHost, aC as pollToolName, aD as readNearestPackageJson, aE as resilientFetch, aF as retryAfterMs, aG as runAction, aH as runConformance, aI as runOptions, aJ as runPoll, aK as withMockHttp } from './check-CzSTEQD8.js';
|
|
3
3
|
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
4
4
|
|
|
5
5
|
/** Everything an extension may ask the host for; anything else is not grantable. */
|
package/dist/index.js
CHANGED