@vornrun/connector-sdk 0.7.0 → 0.7.1-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/dist/{check-62s2GvcO.d.ts → check-CzSTEQD8.d.ts} +2 -0
- package/dist/{chunk-ZKHXHE3O.js → chunk-CCY5QT5R.js} +109 -85
- 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;
|
|
@@ -3450,6 +3474,8 @@ export {
|
|
|
3450
3474
|
createSessionFetch,
|
|
3451
3475
|
ORIGIN_PATTERN,
|
|
3452
3476
|
withinOrigins,
|
|
3477
|
+
valueAt,
|
|
3478
|
+
applyPostReceive,
|
|
3453
3479
|
EXTENSION_PERMISSIONS,
|
|
3454
3480
|
HOST_PERMISSIONS,
|
|
3455
3481
|
envNameFor,
|
|
@@ -3477,8 +3503,6 @@ export {
|
|
|
3477
3503
|
normalizeItem,
|
|
3478
3504
|
normalizeItems,
|
|
3479
3505
|
pollWithDedupe,
|
|
3480
|
-
valueAt,
|
|
3481
|
-
applyPostReceive,
|
|
3482
3506
|
resolveTemplates,
|
|
3483
3507
|
resolveRequest,
|
|
3484
3508
|
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