@zackbart/connecta 0.24.4 → 0.26.0
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/AGENTS.md +43 -12
- package/CHANGELOG.md +524 -0
- package/README.md +32 -15
- package/SECURITY.md +6 -5
- package/bin/connecta.mjs +5 -1
- package/dist/activity.d.ts +10 -3
- package/dist/activity.js +10 -1
- package/dist/advertised-schema.js +53 -0
- package/dist/artifacts/connector.d.ts +55 -0
- package/dist/artifacts/connector.js +724 -0
- package/dist/artifacts/document.js +76 -0
- package/dist/artifacts/guide.js +140 -0
- package/dist/artifacts/html-scan.js +329 -0
- package/dist/artifacts/json.js +68 -0
- package/dist/artifacts/kv-store.d.ts +20 -0
- package/dist/artifacts/kv-store.js +140 -0
- package/dist/artifacts/markdown.js +449 -0
- package/dist/artifacts/module.d.ts +37 -0
- package/dist/artifacts/module.js +60 -0
- package/dist/artifacts/operations.d.ts +195 -0
- package/dist/artifacts/operations.js +944 -0
- package/dist/artifacts/refresh.d.ts +53 -0
- package/dist/artifacts/refresh.js +235 -0
- package/dist/artifacts/routes.js +194 -0
- package/dist/artifacts/types.d.ts +214 -0
- package/dist/artifacts/types.js +22 -0
- package/dist/artifacts/validate.d.ts +62 -0
- package/dist/artifacts/validate.js +652 -0
- package/dist/artifacts.d.ts +6 -0
- package/dist/artifacts.js +9 -0
- package/dist/auth/downstream-oauth.js +490 -106
- package/dist/call-admission.js +139 -113
- package/dist/catalog-service.js +152 -106
- package/dist/catalog.js +297 -38
- package/dist/concurrency.js +24 -23
- package/dist/connector-access.d.ts +18 -4
- package/dist/connector-access.js +65 -20
- package/dist/connector-caller.d.ts +8 -0
- package/dist/connector-caller.js +19 -0
- package/dist/connector-scope.js +6 -37
- package/dist/connectors/api.d.ts +2 -2
- package/dist/connectors/remote-mcp.d.ts +6 -5
- package/dist/connectors/remote-mcp.js +330 -240
- package/dist/credential-contract.d.ts +9 -0
- package/dist/credential-rules.js +2 -2
- package/dist/credentials.d.ts +6 -1
- package/dist/credentials.js +45 -3
- package/dist/errors.d.ts +16 -1
- package/dist/errors.js +28 -0
- package/dist/execute.js +745 -282
- package/dist/executor-admission.d.ts +11 -1
- package/dist/executor-admission.js +145 -63
- package/dist/executors/quickjs-runtime.js +4 -2
- package/dist/executors/quickjs.js +255 -212
- package/dist/fix-prompt.js +37 -0
- package/dist/index.d.ts +72 -7
- package/dist/index.js +281 -26
- package/dist/invocation.js +371 -286
- package/dist/meta-tools.js +213 -94
- package/dist/module-contracts.d.ts +21 -1
- package/dist/oauth-callback-outcome.js +94 -0
- package/dist/oauth-sealing.js +29 -0
- package/dist/operator-ui/fix-prompts.js +87 -0
- package/dist/operator-ui/generated.js +2 -2
- package/dist/operator-ui/model.d.ts +103 -1
- package/dist/operator-ui/setup-commands.js +53 -0
- package/dist/operator-ui/view.js +128 -3
- package/dist/program-source.js +321 -0
- package/dist/providers/notion.js +2 -2
- package/dist/providers/revenuecat.js +32 -5
- package/dist/providers/stripe.d.ts +3 -2
- package/dist/providers/vercel.js +1 -1
- package/dist/registry.d.ts +43 -7
- package/dist/registry.js +434 -288
- package/dist/resumable.js +1291 -0
- package/dist/routes/activity.js +74 -154
- package/dist/routes/actor-labels.js +114 -0
- package/dist/routes/credentials.js +196 -163
- package/dist/routes/mcp.js +228 -112
- package/dist/routes/oauth-management.js +73 -71
- package/dist/routes/oauth.js +44 -16
- package/dist/routes/operator.js +83 -0
- package/dist/routes/shared.d.ts +25 -1
- package/dist/routes/shared.js +20 -2
- package/dist/routes/ui-data.js +211 -0
- package/dist/routes/ui.js +76 -35
- package/dist/run-journal.js +347 -0
- package/dist/runtime/admission.js +43 -0
- package/dist/runtime/call-admission.js +67 -0
- package/dist/runtime/connector-scope.js +72 -0
- package/dist/runtime/run.js +174 -0
- package/dist/runtime/services.js +130 -0
- package/dist/runtime/shared-read.js +106 -0
- package/dist/runtime/storage.js +66 -0
- package/dist/server.js +137 -89
- package/dist/skills.js +28 -9
- package/dist/storage/file.js +39 -2
- package/dist/storage/memory.js +28 -16
- package/dist/timeout.js +39 -43
- package/dist/tool-safety.d.ts +27 -1
- package/dist/tool-safety.js +31 -0
- package/dist/types.d.ts +45 -7
- package/dist/ui.d.ts +25 -4
- package/dist/ui.js +77 -167
- package/dist/url-safety.js +157 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/documentation/architecture.md +367 -16
- package/documentation/auth.md +163 -2
- package/documentation/code-mode.md +274 -56
- package/documentation/meta-tools.md +200 -44
- package/ethos.md +46 -47
- package/examples/worker/AGENTS.md +6 -0
- package/examples/worker/README.md +224 -14
- package/examples/worker/src/d1-activity-row.ts +14 -2
- package/examples/worker/src/d1-activity.ts +4 -2
- package/examples/worker/src/d1-storage.ts +116 -0
- package/examples/worker/src/index.ts +42 -7
- package/examples/worker/src/r2-artifact-blobs.ts +29 -0
- package/examples/worker/wrangler.jsonc +21 -5
- package/package.json +16 -4
- package/templates/node/AGENTS.md +9 -2
- package/templates/node/README.md +31 -3
- package/templates/node/package.json +1 -1
- package/templates/node/src/index.ts +27 -0
- package/dist/auth/downstream-oauth.d.ts +0 -200
- package/dist/catalog-fingerprint.d.ts +0 -19
- package/dist/catalog-limits.d.ts +0 -9
- package/dist/catalog-service.d.ts +0 -263
- package/dist/catalog.d.ts +0 -87
- package/dist/concurrency.d.ts +0 -3
- package/dist/connectors/guarded-fetch.d.ts +0 -96
- package/dist/credential-rules.d.ts +0 -85
- package/dist/execute.d.ts +0 -154
- package/dist/executor-result.d.ts +0 -10
- package/dist/executors/quickjs-child.d.ts +0 -1
- package/dist/executors/quickjs-protocol.d.ts +0 -67
- package/dist/favicon.d.ts +0 -1
- package/dist/identity.d.ts +0 -4
- package/dist/invocation.d.ts +0 -74
- package/dist/mcp-result.d.ts +0 -8
- package/dist/meta-tools.d.ts +0 -129
- package/dist/operator-ui/generated.d.ts +0 -2
- package/dist/operator-ui/view.d.ts +0 -188
- package/dist/result-shapes.d.ts +0 -13
- package/dist/retired-toolkits.d.ts +0 -2
- package/dist/routes/activity.d.ts +0 -2
- package/dist/routes/credentials.d.ts +0 -2
- package/dist/routes/mcp.d.ts +0 -10
- package/dist/routes/oauth-management.d.ts +0 -2
- package/dist/routes/oauth.d.ts +0 -2
- package/dist/routes/ui.d.ts +0 -2
- package/dist/server.d.ts +0 -9
- package/dist/skills.d.ts +0 -44
- package/dist/timeout.d.ts +0 -21
package/dist/catalog.js
CHANGED
|
@@ -14,6 +14,12 @@ class SchemaWork {
|
|
|
14
14
|
remaining = MAX_SCHEMA_WORK;
|
|
15
15
|
truncated = false;
|
|
16
16
|
refs = new Map();
|
|
17
|
+
/**
|
|
18
|
+
* Renderings whose top level is a bare `|` or `&`, recorded as the walk
|
|
19
|
+
* produces them. Compact carries raw keys and `//` prose, so unlike the
|
|
20
|
+
* TypeScript dialect its text cannot be rescanned for a top-level operator.
|
|
21
|
+
*/
|
|
22
|
+
ungrouped = new Set();
|
|
17
23
|
constructor(byteLimit = MAX_COMPACT_DISCOVERY_SCHEMA_BYTES) {
|
|
18
24
|
this.byteLimit = byteLimit;
|
|
19
25
|
}
|
|
@@ -35,11 +41,29 @@ class SchemaWork {
|
|
|
35
41
|
const visit = this.visit.bind(this);
|
|
36
42
|
const text = this.text.bind(this);
|
|
37
43
|
const ancestors = [];
|
|
44
|
+
let serializedBytes = 0;
|
|
45
|
+
const addSerialized = (value) => {
|
|
46
|
+
serializedBytes += schemaEncoder.encode(value).length;
|
|
47
|
+
if (serializedBytes > this.byteLimit)
|
|
48
|
+
throw schemaSizeExceeded;
|
|
49
|
+
};
|
|
38
50
|
return this.text(JSON.stringify(value, function (key, item) {
|
|
39
51
|
visit();
|
|
40
52
|
text(key);
|
|
41
53
|
if (typeof item === "string")
|
|
42
54
|
text(item);
|
|
55
|
+
const omitted = item === undefined || typeof item === "function" || typeof item === "symbol";
|
|
56
|
+
const root = key === "" && ancestors.length === 0;
|
|
57
|
+
if (!omitted) {
|
|
58
|
+
// Array indexes are implicit in JSON. Object keys and primitive values
|
|
59
|
+
// are the useful lower bound; the final text check remains authoritative
|
|
60
|
+
// for braces, commas, and values whose encoding is larger than this bound.
|
|
61
|
+
if (!root && !Array.isArray(this))
|
|
62
|
+
addSerialized(JSON.stringify(key));
|
|
63
|
+
if (typeof item !== "object" || item === null) {
|
|
64
|
+
addSerialized(JSON.stringify(item));
|
|
65
|
+
}
|
|
66
|
+
}
|
|
43
67
|
if (item !== null && typeof item === "object") {
|
|
44
68
|
while (ancestors.length && ancestors[ancestors.length - 1] !== this) {
|
|
45
69
|
ancestors.pop();
|
|
@@ -417,8 +441,11 @@ function renderEnum(values, work, byteLimit, onTruncated) {
|
|
|
417
441
|
const full = prefix.join(" | ");
|
|
418
442
|
if (schemaEncoder.encode(full).length > limit)
|
|
419
443
|
break;
|
|
420
|
-
if (index === values.length - 1)
|
|
444
|
+
if (index === values.length - 1) {
|
|
445
|
+
if (index > 0)
|
|
446
|
+
work.ungrouped.add(full);
|
|
421
447
|
return full;
|
|
448
|
+
}
|
|
422
449
|
const omitted = values.length - prefix.length;
|
|
423
450
|
const candidate = `(${full} | ${marker(omitted)})`;
|
|
424
451
|
if (schemaEncoder.encode(candidate).length <= limit)
|
|
@@ -481,20 +508,131 @@ function renderConstraints(base, schema, byteLimit, onTruncated) {
|
|
|
481
508
|
? base
|
|
482
509
|
: `${grouped(base)} /* ${kept.join("; ")} */`;
|
|
483
510
|
}
|
|
511
|
+
/**
|
|
512
|
+
* `grouped` for the TypeScript dialect, whose JSDoc prose and string literals
|
|
513
|
+
* may carry unbalanced brackets from a downstream description: skipping both
|
|
514
|
+
* keeps a stray `)` in prose from hiding a real top-level union.
|
|
515
|
+
*/
|
|
516
|
+
function groupedType(part) {
|
|
517
|
+
let nesting = 0;
|
|
518
|
+
for (let i = 0; i < part.length; i += 1) {
|
|
519
|
+
const char = part[i];
|
|
520
|
+
if (part.startsWith("/*", i)) {
|
|
521
|
+
const end = part.indexOf("*/", i + 2);
|
|
522
|
+
if (end < 0)
|
|
523
|
+
break;
|
|
524
|
+
i = end + 1;
|
|
525
|
+
}
|
|
526
|
+
else if (char === '"') {
|
|
527
|
+
for (i += 1; i < part.length && part[i] !== '"'; i += 1) {
|
|
528
|
+
if (part[i] === "\\")
|
|
529
|
+
i += 1;
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
else if (char === "{" || char === "(" || char === "[" || char === "<") {
|
|
533
|
+
nesting += 1;
|
|
534
|
+
}
|
|
535
|
+
else if (char === "}" || char === ")" || char === "]" || char === ">") {
|
|
536
|
+
nesting -= 1;
|
|
537
|
+
}
|
|
538
|
+
else if (nesting === 0 &&
|
|
539
|
+
(part.startsWith(" | ", i) || part.startsWith(" & ", i))) {
|
|
540
|
+
return `(${part})`;
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
return part;
|
|
544
|
+
}
|
|
545
|
+
const TYPESCRIPT_IDENTIFIER = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
|
|
546
|
+
function typescriptKey(key) {
|
|
547
|
+
return TYPESCRIPT_IDENTIFIER.test(key) ? key : JSON.stringify(key);
|
|
548
|
+
}
|
|
549
|
+
/** One-line JSDoc body; downstream prose can never close the comment early. */
|
|
550
|
+
function typescriptDoc(text) {
|
|
551
|
+
return text.replace(/\s+/g, " ").trim().replaceAll("*/", "*\\/");
|
|
552
|
+
}
|
|
553
|
+
function typescriptPrimitive(type) {
|
|
554
|
+
if (type === "integer")
|
|
555
|
+
return "number";
|
|
556
|
+
if (type === "array")
|
|
557
|
+
return "unknown[]";
|
|
558
|
+
if (type === "object")
|
|
559
|
+
return "Record<string, unknown>";
|
|
560
|
+
return ["string", "number", "boolean", "null"].includes(type)
|
|
561
|
+
? type
|
|
562
|
+
: "unknown";
|
|
563
|
+
}
|
|
564
|
+
function boundedParts(work, separator, prefix, suffix) {
|
|
565
|
+
// Check each addition before joining so a rejected schema never creates a
|
|
566
|
+
// large intermediate string just to discover that the final result is over.
|
|
567
|
+
const parts = [];
|
|
568
|
+
let bytes = schemaEncoder.encode(prefix).length + schemaEncoder.encode(suffix).length;
|
|
569
|
+
const separatorBytes = schemaEncoder.encode(separator).length;
|
|
570
|
+
return {
|
|
571
|
+
get length() {
|
|
572
|
+
return parts.length;
|
|
573
|
+
},
|
|
574
|
+
add(part) {
|
|
575
|
+
const partBytes = schemaEncoder.encode(part).length;
|
|
576
|
+
const added = partBytes + (parts.length > 0 ? separatorBytes : 0);
|
|
577
|
+
if (bytes + added > work.byteLimit)
|
|
578
|
+
throw schemaSizeExceeded;
|
|
579
|
+
parts.push(part);
|
|
580
|
+
bytes += added;
|
|
581
|
+
},
|
|
582
|
+
finish() {
|
|
583
|
+
return `${prefix}${parts.join(separator)}${suffix}`;
|
|
584
|
+
},
|
|
585
|
+
};
|
|
586
|
+
}
|
|
484
587
|
function renderSchema(schema, defs, seen, depth, options) {
|
|
485
588
|
options.work.visit();
|
|
486
589
|
return options.work.text(renderSchemaNode(schema, defs, seen, depth, options));
|
|
487
590
|
}
|
|
488
591
|
function renderSchemaNode(schema, defs, seen, depth, options) {
|
|
489
|
-
|
|
490
|
-
|
|
592
|
+
const ts = options.typescript === true;
|
|
593
|
+
const group = ts ? groupedType : grouped;
|
|
594
|
+
const ungrouped = options.work.ungrouped;
|
|
595
|
+
// A `[]` suffix binds tighter than `|` and `&`, so an element rendered at
|
|
596
|
+
// operator level needs parentheses or it reads as its last member's array.
|
|
597
|
+
const element = (rendered) => ts
|
|
598
|
+
? groupedType(rendered)
|
|
599
|
+
: ungrouped.has(rendered) ? `(${rendered})` : rendered;
|
|
600
|
+
if (depth > 4) {
|
|
601
|
+
if (!ts)
|
|
602
|
+
return "…";
|
|
603
|
+
options.work.truncated = true;
|
|
604
|
+
return `unknown${COMPACT_DISCOVERY_TRUNCATION}`;
|
|
605
|
+
}
|
|
491
606
|
if (schema === null || typeof schema !== "object") {
|
|
607
|
+
if (ts)
|
|
608
|
+
return schema === false ? "never" : "unknown";
|
|
492
609
|
return options.work.json(schema);
|
|
493
610
|
}
|
|
494
611
|
const s = schema;
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
612
|
+
// OpenAPI 3.0's `nullable` has no JSON Schema meaning, so compact ignores
|
|
613
|
+
// it; a TypeScript reader writing `null` checks needs it in the type.
|
|
614
|
+
if (ts && s.nullable === true) {
|
|
615
|
+
const base = Object.create(null);
|
|
616
|
+
for (const key of propertyNames(s, options.work)) {
|
|
617
|
+
if (key !== "nullable")
|
|
618
|
+
base[key] = s[key];
|
|
619
|
+
}
|
|
620
|
+
const rendered = declaresShape(base)
|
|
621
|
+
? renderSchema(base, defs, seen, depth, options)
|
|
622
|
+
: "unknown";
|
|
623
|
+
return rendered === "unknown" ? rendered : `${rendered} | null`;
|
|
624
|
+
}
|
|
625
|
+
const constrain = (rendered) => {
|
|
626
|
+
if (!options.renderConstraints)
|
|
627
|
+
return rendered;
|
|
628
|
+
const result = renderConstraints(rendered, s, options.constraintByteLimit, options.onConstraintTruncated);
|
|
629
|
+
// Constraints parenthesize a union before their comment but leave an
|
|
630
|
+
// intersection bare, and a comment does not group what precedes it.
|
|
631
|
+
if (ungrouped.has(rendered) && !result.startsWith(`(${rendered})`)) {
|
|
632
|
+
ungrouped.add(result);
|
|
633
|
+
}
|
|
634
|
+
return result;
|
|
635
|
+
};
|
|
498
636
|
// Conditions cannot be expressed by a single static shape. Preserve the
|
|
499
637
|
// base and send callers to the exact schema instead of hiding the rules.
|
|
500
638
|
if (s.dependentSchemas !== undefined || s.if !== undefined ||
|
|
@@ -508,7 +646,10 @@ function renderSchemaNode(schema, defs, seen, depth, options) {
|
|
|
508
646
|
const rendered = declaresShape(base)
|
|
509
647
|
? renderSchema(base, defs, seen, depth, options)
|
|
510
648
|
: "unknown";
|
|
511
|
-
|
|
649
|
+
const result = `${rendered} /* conditional */`;
|
|
650
|
+
if (ungrouped.has(rendered))
|
|
651
|
+
ungrouped.add(result);
|
|
652
|
+
return result;
|
|
512
653
|
}
|
|
513
654
|
// allOf composes rather than replaces: it is checked before every other
|
|
514
655
|
// shape keyword, and renders the schema's own shape alongside its members instead
|
|
@@ -524,29 +665,44 @@ function renderSchemaNode(schema, defs, seen, depth, options) {
|
|
|
524
665
|
if (key !== "allOf")
|
|
525
666
|
own[key] = s[key];
|
|
526
667
|
}
|
|
527
|
-
const parts =
|
|
528
|
-
|
|
529
|
-
|
|
668
|
+
const parts = boundedParts(options.work, " & ", "", "");
|
|
669
|
+
const groupParts = declaresShape(own)
|
|
670
|
+
? s.allOf.length > 0
|
|
671
|
+
: s.allOf.length > 1;
|
|
672
|
+
if (declaresShape(own)) {
|
|
673
|
+
const rendered = renderSchema(own, defs, seen, depth, options);
|
|
674
|
+
parts.add(groupParts ? group(rendered) : rendered);
|
|
675
|
+
}
|
|
530
676
|
for (const member of s.allOf) {
|
|
531
|
-
|
|
677
|
+
const rendered = renderSchema(member, defs, seen, depth + 1, options);
|
|
678
|
+
parts.add(groupParts ? group(rendered) : rendered);
|
|
532
679
|
}
|
|
533
680
|
if (parts.length === 0)
|
|
534
681
|
return "unknown";
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
682
|
+
const rendered = parts.finish();
|
|
683
|
+
if (parts.length > 1)
|
|
684
|
+
ungrouped.add(rendered);
|
|
685
|
+
return rendered;
|
|
538
686
|
}
|
|
539
687
|
const reference = s.$ref ?? s.$dynamicRef;
|
|
540
688
|
if (typeof reference === "string") {
|
|
541
689
|
const dynamic = s.$ref === undefined;
|
|
542
690
|
const rawName = refName(options.work.text(reference));
|
|
543
691
|
const name = dynamic ? rawName.replace(/^#/, "") : rawName;
|
|
544
|
-
if (seen.has(name))
|
|
545
|
-
|
|
692
|
+
if (seen.has(name)) {
|
|
693
|
+
if (!ts)
|
|
694
|
+
return name;
|
|
695
|
+
// A cycle has no finite TypeScript expansion, and a bare definition
|
|
696
|
+
// name would be an undeclared type: degrade and send callers to JSON.
|
|
697
|
+
options.work.truncated = true;
|
|
698
|
+
return "unknown /* recursive */";
|
|
699
|
+
}
|
|
546
700
|
const target = resolveDefinition(defs, name);
|
|
547
701
|
if (target === undefined) {
|
|
548
|
-
if (dynamic)
|
|
702
|
+
if (dynamic || ts)
|
|
549
703
|
options.work.truncated = true;
|
|
704
|
+
if (ts)
|
|
705
|
+
return "unknown /* unresolved */";
|
|
550
706
|
return dynamic ? "unknown" : name;
|
|
551
707
|
}
|
|
552
708
|
const cacheKey = JSON.stringify([name, depth, [...seen]]);
|
|
@@ -561,10 +717,13 @@ function renderSchemaNode(schema, defs, seen, depth, options) {
|
|
|
561
717
|
}
|
|
562
718
|
const union = (s.oneOf ?? s.anyOf);
|
|
563
719
|
if (Array.isArray(union)) {
|
|
564
|
-
const
|
|
565
|
-
|
|
566
|
-
.
|
|
567
|
-
|
|
720
|
+
const parts = boundedParts(options.work, " | ", "", "");
|
|
721
|
+
for (const member of union) {
|
|
722
|
+
parts.add(renderSchema(member, defs, seen, depth + 1, options));
|
|
723
|
+
}
|
|
724
|
+
const rendered = parts.finish() || "unknown";
|
|
725
|
+
if (parts.length > 1)
|
|
726
|
+
ungrouped.add(rendered);
|
|
568
727
|
return constrain(rendered);
|
|
569
728
|
}
|
|
570
729
|
if (Array.isArray(s.enum)) {
|
|
@@ -580,21 +739,50 @@ function renderSchemaNode(schema, defs, seen, depth, options) {
|
|
|
580
739
|
return constrain(rendered);
|
|
581
740
|
}
|
|
582
741
|
const type = s.type;
|
|
742
|
+
// A type list renders member by member, so `["object", "null"]` beside
|
|
743
|
+
// `properties` keeps both its shape and its null rather than the object alone.
|
|
744
|
+
if (ts && Array.isArray(type) && type.length > 0) {
|
|
745
|
+
const members = new Set();
|
|
746
|
+
const parts = boundedParts(options.work, " | ", "", "");
|
|
747
|
+
for (const item of type) {
|
|
748
|
+
options.work.visit();
|
|
749
|
+
if (typeof item !== "string")
|
|
750
|
+
continue;
|
|
751
|
+
let rendered = "null";
|
|
752
|
+
if (item !== "null") {
|
|
753
|
+
const member = Object.create(null);
|
|
754
|
+
for (const key of propertyNames(s, options.work)) {
|
|
755
|
+
if (key !== "type")
|
|
756
|
+
member[key] = s[key];
|
|
757
|
+
}
|
|
758
|
+
member.type = item;
|
|
759
|
+
rendered = renderSchema(member, defs, seen, depth, options);
|
|
760
|
+
}
|
|
761
|
+
if (members.has(rendered))
|
|
762
|
+
continue;
|
|
763
|
+
members.add(rendered);
|
|
764
|
+
parts.add(rendered);
|
|
765
|
+
}
|
|
766
|
+
return parts.length === 0 ? "unknown" : parts.finish();
|
|
767
|
+
}
|
|
583
768
|
if (Array.isArray(s.prefixItems)) {
|
|
584
|
-
const parts =
|
|
769
|
+
const parts = boundedParts(options.work, ", ", "[", "]");
|
|
770
|
+
for (const item of s.prefixItems) {
|
|
771
|
+
parts.add(renderSchema(item, defs, seen, depth + 1, options));
|
|
772
|
+
}
|
|
585
773
|
if (s.items !== false) {
|
|
586
774
|
const rest = s.items === undefined || s.items === true
|
|
587
775
|
? "unknown"
|
|
588
776
|
: renderSchema(s.items, defs, seen, depth + 1, options);
|
|
589
|
-
parts.
|
|
777
|
+
parts.add(`...${element(rest)}[]`);
|
|
590
778
|
}
|
|
591
|
-
return
|
|
779
|
+
return parts.finish();
|
|
592
780
|
}
|
|
593
781
|
if (type === "array" || s.items) {
|
|
594
782
|
const items = s.items
|
|
595
783
|
? renderSchema(s.items, defs, seen, depth + 1, options)
|
|
596
784
|
: "unknown";
|
|
597
|
-
return `${items}[]`;
|
|
785
|
+
return `${element(items)}[]`;
|
|
598
786
|
}
|
|
599
787
|
if (type === "object" || s.properties) {
|
|
600
788
|
const props = (s.properties ?? {});
|
|
@@ -606,10 +794,17 @@ function renderSchemaNode(schema, defs, seen, depth, options) {
|
|
|
606
794
|
...declaredKeys.filter((key) => !required.has(key)),
|
|
607
795
|
]
|
|
608
796
|
: declaredKeys;
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
797
|
+
const additional = s.additionalProperties;
|
|
798
|
+
const index = ts && additional !== null && typeof additional === "object"
|
|
799
|
+
? renderSchema(additional, defs, seen, depth + 1, options)
|
|
800
|
+
: undefined;
|
|
801
|
+
if (keys.length === 0 && index === undefined) {
|
|
802
|
+
// In TypeScript `{}` reads as "empty"; an object with no declared
|
|
803
|
+
// properties is an open map unless it closes itself explicitly.
|
|
804
|
+
return ts && additional !== false ? "Record<string, unknown>" : "{}";
|
|
805
|
+
}
|
|
806
|
+
const parts = boundedParts(options.work, ts ? "; " : ", ", "{ ", " }");
|
|
807
|
+
for (const key of keys) {
|
|
613
808
|
const optional = required.has(key) ? "" : "?";
|
|
614
809
|
const rendered = renderSchema(props[key], defs, seen, depth + 1, options);
|
|
615
810
|
const description = props[key]?.description;
|
|
@@ -617,27 +812,42 @@ function renderSchemaNode(schema, defs, seen, depth, options) {
|
|
|
617
812
|
options.work.text(description);
|
|
618
813
|
}
|
|
619
814
|
options.work.text(key);
|
|
815
|
+
if (ts) {
|
|
816
|
+
const doc = options.propertyDescriptions && typeof description === "string" &&
|
|
817
|
+
description.trim()
|
|
818
|
+
? `/** ${typescriptDoc(description)} */ `
|
|
819
|
+
: "";
|
|
820
|
+
parts.add(`${doc}${typescriptKey(key)}${optional}: ${rendered}`);
|
|
821
|
+
continue;
|
|
822
|
+
}
|
|
620
823
|
const comment = options.propertyDescriptions && typeof description === "string"
|
|
621
824
|
? ` // ${description}`
|
|
622
825
|
: "";
|
|
623
|
-
|
|
624
|
-
}
|
|
625
|
-
|
|
826
|
+
parts.add(`${key}${optional}: ${rendered}${comment}`);
|
|
827
|
+
}
|
|
828
|
+
if (index !== undefined)
|
|
829
|
+
parts.add(`[key: string]: ${index}`);
|
|
830
|
+
return parts.finish();
|
|
626
831
|
}
|
|
627
832
|
if (typeof type === "string") {
|
|
628
|
-
|
|
833
|
+
const text = options.work.text(type);
|
|
834
|
+
return constrain(ts ? typescriptPrimitive(text) : text);
|
|
629
835
|
}
|
|
630
836
|
if (Array.isArray(type)) {
|
|
631
|
-
const
|
|
837
|
+
const parts = boundedParts(options.work, " | ", "", "");
|
|
838
|
+
for (const item of type) {
|
|
632
839
|
options.work.visit();
|
|
633
|
-
|
|
634
|
-
}
|
|
840
|
+
parts.add(options.work.text(String(item)));
|
|
841
|
+
}
|
|
842
|
+
const rendered = parts.finish();
|
|
843
|
+
if (parts.length > 1)
|
|
844
|
+
ungrouped.add(rendered);
|
|
635
845
|
return constrain(rendered);
|
|
636
846
|
}
|
|
637
847
|
if (options.renderConstraints && constraintEntries(s).length > 0) {
|
|
638
848
|
return renderConstraints("unknown", s, options.constraintByteLimit, options.onConstraintTruncated);
|
|
639
849
|
}
|
|
640
|
-
return options.work.json(schema);
|
|
850
|
+
return ts ? "unknown" : options.work.json(schema);
|
|
641
851
|
}
|
|
642
852
|
const compactSchemas = new WeakMap();
|
|
643
853
|
function resolveDefinition(schema, name) {
|
|
@@ -713,10 +923,58 @@ export function compactDiscoverySchema(schema) {
|
|
|
713
923
|
compactDiscoverySchemas.set(schema, result);
|
|
714
924
|
return result;
|
|
715
925
|
}
|
|
716
|
-
|
|
926
|
+
const typescriptDiscoveryTypes = new WeakMap();
|
|
927
|
+
const typescriptDescriptionTypes = new WeakMap();
|
|
928
|
+
/**
|
|
929
|
+
* One schema as a TypeScript type, under exactly the compact budgets: search
|
|
930
|
+
* drops prose and orders required keys first within 1,024 bytes, describe
|
|
931
|
+
* keeps prose as JSDoc within 8,192, and both share the 2,000-visit walk.
|
|
932
|
+
*/
|
|
933
|
+
function typescriptType(schema, description) {
|
|
934
|
+
const cache = description ? typescriptDescriptionTypes : typescriptDiscoveryTypes;
|
|
935
|
+
const cached = cache.get(schema);
|
|
936
|
+
if (cached)
|
|
937
|
+
return cached;
|
|
938
|
+
const result = boundedCompactSchema(schema, description, true);
|
|
939
|
+
cache.set(schema, result);
|
|
940
|
+
return result;
|
|
941
|
+
}
|
|
942
|
+
/** Marks runtime evidence inside the signature itself, not only beside it. */
|
|
943
|
+
const OBSERVED_OUTPUT_MARKER = "/* observed, not declared */ ";
|
|
944
|
+
/**
|
|
945
|
+
* Render a tool as the function `connecta.call(address, args)` resolves to,
|
|
946
|
+
* for an agent to read — never to execute: code mode still runs JavaScript.
|
|
947
|
+
*
|
|
948
|
+
* The input half comes from the declared input schema. The output half is the
|
|
949
|
+
* declared output schema, else a passively observed shape carrying a leading
|
|
950
|
+
* marker (runtime evidence is never presented as a contract), else `unknown`.
|
|
951
|
+
* A zero-field input renders as the optional `args?: {}` that call accepts:
|
|
952
|
+
* an MCP tool with no parameters rarely closes its schema, and reading its
|
|
953
|
+
* open `Record<string, unknown>` as "pass anything" would invite guessing.
|
|
954
|
+
*/
|
|
955
|
+
export function typescriptSignature(input, output, options) {
|
|
956
|
+
const renderedInput = typescriptType(input, options.description);
|
|
957
|
+
const renderedOutput = output
|
|
958
|
+
? typescriptType(output, options.description)
|
|
959
|
+
: undefined;
|
|
960
|
+
const args = renderedInput.text === "{}" ||
|
|
961
|
+
renderedInput.text === "Record<string, unknown>"
|
|
962
|
+
? "args?: {}"
|
|
963
|
+
: `args: ${renderedInput.text}`;
|
|
964
|
+
const result = renderedOutput
|
|
965
|
+
? `${options.observed ? OBSERVED_OUTPUT_MARKER : ""}${renderedOutput.text}`
|
|
966
|
+
: "unknown";
|
|
967
|
+
return {
|
|
968
|
+
text: `(${args}) => Promise<${result}>`,
|
|
969
|
+
inputTruncated: renderedInput.truncated,
|
|
970
|
+
outputTruncated: renderedOutput?.truncated === true,
|
|
971
|
+
};
|
|
972
|
+
}
|
|
973
|
+
function boundedCompactSchema(schema, description, typescript = false) {
|
|
717
974
|
const work = new SchemaWork(description ? MAX_COMPACT_DESCRIPTION_SCHEMA_BYTES : MAX_COMPACT_DISCOVERY_SCHEMA_BYTES);
|
|
718
975
|
const options = {
|
|
719
976
|
work,
|
|
977
|
+
typescript,
|
|
720
978
|
propertyDescriptions: description,
|
|
721
979
|
requiredFirst: !description,
|
|
722
980
|
enumByteLimit: description ? work.byteLimit : MAX_COMPACT_DISCOVERY_ENUM_BYTES,
|
|
@@ -734,6 +992,7 @@ function boundedCompactSchema(schema, description) {
|
|
|
734
992
|
// are memoized only within each pass because their text includes constraints.
|
|
735
993
|
if (error === schemaSizeExceeded && !description) {
|
|
736
994
|
work.refs.clear();
|
|
995
|
+
work.ungrouped.clear();
|
|
737
996
|
try {
|
|
738
997
|
return {
|
|
739
998
|
text: renderSchema(schema, schema, new Set(), 0, {
|
package/dist/concurrency.js
CHANGED
|
@@ -1,30 +1,31 @@
|
|
|
1
|
+
import { Effect } from "effect";
|
|
2
|
+
import { runEdge } from "./runtime/run.js";
|
|
1
3
|
const DEFAULT_DISCOVERY_CONCURRENCY = 4;
|
|
2
4
|
export function resolveDiscoveryConcurrency(value) {
|
|
3
5
|
return value !== undefined && Number.isInteger(value) && value > 0
|
|
4
6
|
? value
|
|
5
7
|
: DEFAULT_DISCOVERY_CONCURRENCY;
|
|
6
8
|
}
|
|
7
|
-
/**
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
return settled;
|
|
9
|
+
/**
|
|
10
|
+
* Run `fn` over `items` with at most `limit` operations in flight, settling
|
|
11
|
+
* every one: a rejection lands in its slot instead of cancelling the rest.
|
|
12
|
+
* Results keep input order whatever order the work finishes in. A limit below
|
|
13
|
+
* one runs the items one at a time.
|
|
14
|
+
*/
|
|
15
|
+
export function mapSettledWithConcurrency(items, limit, fn) {
|
|
16
|
+
return runEdge(Effect.forEach(items, (item, index) => Effect.tryPromise({
|
|
17
|
+
// Promise.resolve keeps a non-promise return from `fn` working, as
|
|
18
|
+
// `await` did; a synchronous throw is caught either way.
|
|
19
|
+
try: () => Promise.resolve(fn(item, index)),
|
|
20
|
+
catch: (reason) => reason,
|
|
21
|
+
}).pipe(Effect.match({
|
|
22
|
+
onSuccess: (value) => ({
|
|
23
|
+
status: "fulfilled",
|
|
24
|
+
value,
|
|
25
|
+
}),
|
|
26
|
+
onFailure: (reason) => ({
|
|
27
|
+
status: "rejected",
|
|
28
|
+
reason,
|
|
29
|
+
}),
|
|
30
|
+
})), { concurrency: limit >= 1 ? Math.floor(limit) : 1 }));
|
|
30
31
|
}
|
|
@@ -9,20 +9,33 @@ export declare const POOL_NAME_RE: RegExp;
|
|
|
9
9
|
/**
|
|
10
10
|
* One derived view: which connectors, and for connectors granted by address
|
|
11
11
|
* only, which tools. A connector absent from `toolAccess` is visible whole.
|
|
12
|
+
* `guardedToolAccess` is a subset of `toolAccess` checked against the loaded
|
|
13
|
+
* catalog each time tools are discovered or invoked.
|
|
12
14
|
*/
|
|
13
15
|
export interface ConnectorAccess {
|
|
14
16
|
connectorIds: "all" | readonly string[];
|
|
15
17
|
toolAccess?: ToolAccess;
|
|
18
|
+
/** Exact tool grants that also require a current explicit read-only annotation. */
|
|
19
|
+
guardedToolAccess?: ToolAccess;
|
|
16
20
|
}
|
|
21
|
+
interface ReadOnlyToolGrant {
|
|
22
|
+
tool: string;
|
|
23
|
+
requireReadOnly: true;
|
|
24
|
+
}
|
|
25
|
+
export type ConnectorGrant = string | ReadOnlyToolGrant;
|
|
17
26
|
/**
|
|
18
27
|
* Normalize a grant list. A bare connector id grants every tool on that
|
|
19
28
|
* connector; a `connector.tool` address grants one tool. Grants are additive,
|
|
20
29
|
* so a bare id beside addresses for the same connector means the whole
|
|
21
|
-
* connector.
|
|
22
|
-
*
|
|
23
|
-
*
|
|
30
|
+
* connector. Identity resolution can opt into `{ tool, requireReadOnly: true }`
|
|
31
|
+
* for a fixed address that also needs a current explicit read-only annotation;
|
|
32
|
+
* pool declarations remain strings. Anything else throws, and the caller
|
|
33
|
+
* decides whether that is a construction failure or a 403: a grant that
|
|
34
|
+
* cannot be parsed must never fail open.
|
|
24
35
|
*/
|
|
25
|
-
export declare function parseConnectorAccess(value: unknown
|
|
36
|
+
export declare function parseConnectorAccess(value: unknown, options?: {
|
|
37
|
+
allowReadOnly?: boolean;
|
|
38
|
+
}): ConnectorAccess;
|
|
26
39
|
/**
|
|
27
40
|
* The view a pool endpoint serves: the pool's grants, never wider than the
|
|
28
41
|
* identity's own. A connector or tool outside either side is gone; a
|
|
@@ -30,3 +43,4 @@ export declare function parseConnectorAccess(value: unknown): ConnectorAccess;
|
|
|
30
43
|
* only narrow what the identity resolver already allowed.
|
|
31
44
|
*/
|
|
32
45
|
export declare function intersectAccess(ceiling: ConnectorAccess, pool: ConnectorAccess): ConnectorAccess;
|
|
46
|
+
export {};
|