@frontmcp/adapters 1.1.2 → 1.2.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/esm/index.mjs +396 -385
- package/esm/openapi/index.mjs +396 -385
- package/esm/package.json +18 -6
- package/esm/skills/index.mjs +2117 -0
- package/index.js +407 -389
- package/openapi/index.d.ts +11 -1
- package/openapi/index.d.ts.map +1 -1
- package/openapi/index.js +407 -389
- package/openapi/openapi.adapter.d.ts +2 -2
- package/openapi/openapi.adapter.d.ts.map +1 -1
- package/openapi/openapi.tool.d.ts.map +1 -1
- package/openapi/openapi.types.d.ts +3 -3
- package/openapi/openapi.types.d.ts.map +1 -1
- package/openapi/openapi.utils.d.ts.map +1 -1
- package/package.json +18 -6
- package/skills/audit/audit-chain.d.ts +81 -0
- package/skills/audit/audit-chain.d.ts.map +1 -0
- package/skills/audit/audit-config.d.ts +87 -0
- package/skills/audit/audit-config.d.ts.map +1 -0
- package/skills/audit/audit-record.types.d.ts +114 -0
- package/skills/audit/audit-record.types.d.ts.map +1 -0
- package/skills/audit/audit-signer.d.ts +72 -0
- package/skills/audit/audit-signer.d.ts.map +1 -0
- package/skills/audit/audit-store.d.ts +84 -0
- package/skills/audit/audit-store.d.ts.map +1 -0
- package/skills/audit/audit-writer.d.ts +175 -0
- package/skills/audit/audit-writer.d.ts.map +1 -0
- package/skills/audit/index.d.ts +7 -0
- package/skills/audit/index.d.ts.map +1 -0
- package/skills/bundle/bundle-diff.d.ts +30 -0
- package/skills/bundle/bundle-diff.d.ts.map +1 -0
- package/skills/bundle/bundle.schema.d.ts +101 -0
- package/skills/bundle/bundle.schema.d.ts.map +1 -0
- package/skills/bundle/bundle.store.d.ts +143 -0
- package/skills/bundle/bundle.store.d.ts.map +1 -0
- package/skills/bundle/bundle.types.d.ts +143 -0
- package/skills/bundle/bundle.types.d.ts.map +1 -0
- package/skills/bundle/overlay-parser.d.ts +42 -0
- package/skills/bundle/overlay-parser.d.ts.map +1 -0
- package/skills/dependency/skill-dag.d.ts +39 -0
- package/skills/dependency/skill-dag.d.ts.map +1 -0
- package/skills/index.d.ts +17 -0
- package/skills/index.d.ts.map +1 -0
- package/skills/index.js +2192 -0
- package/skills/security/bundle-signature.d.ts +44 -0
- package/skills/security/bundle-signature.d.ts.map +1 -0
- package/skills/security/jwt-verifier.d.ts +38 -0
- package/skills/security/jwt-verifier.d.ts.map +1 -0
- package/skills/security/webhook-replay-guard.d.ts +52 -0
- package/skills/security/webhook-replay-guard.d.ts.map +1 -0
- package/skills/source-options.d.ts +55 -0
- package/skills/source-options.d.ts.map +1 -0
- package/skills/sources/filesystem-skills.source.d.ts +127 -0
- package/skills/sources/filesystem-skills.source.d.ts.map +1 -0
- package/skills/sources/index.d.ts +10 -0
- package/skills/sources/index.d.ts.map +1 -0
- package/skills/sources/npm.source.d.ts +30 -0
- package/skills/sources/npm.source.d.ts.map +1 -0
- package/skills/sources/saas-pull.source.d.ts +47 -0
- package/skills/sources/saas-pull.source.d.ts.map +1 -0
- package/skills/sources/skill-bundle-source.interface.d.ts +36 -0
- package/skills/sources/skill-bundle-source.interface.d.ts.map +1 -0
- package/skills/sources/static.source.d.ts +30 -0
- package/skills/sources/static.source.d.ts.map +1 -0
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import type { SkillAuditSubjectMode } from './audit-config';
|
|
2
|
+
import { SKILL_AUDIT_GENESIS_PREV_HASH } from './audit-record.types';
|
|
3
|
+
import type { SkillAuditSigner } from './audit-signer';
|
|
4
|
+
import type { SkillAuditStore } from './audit-store';
|
|
5
|
+
/**
|
|
6
|
+
* Minimal logger surface — matches `FrontMcpLogger` but we don't import it
|
|
7
|
+
* here to keep the audit module shippable without an SDK dependency.
|
|
8
|
+
*/
|
|
9
|
+
export interface SkillAuditLogger {
|
|
10
|
+
warn(...args: unknown[]): void;
|
|
11
|
+
debug?(...args: unknown[]): void;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Optional metrics counter. When wired (e.g. by the telemetry agent) a
|
|
15
|
+
* failed audit write increments
|
|
16
|
+
* `frontmcp_skills_audit_write_failures_total{reason}` and a dropped record
|
|
17
|
+
* (queue overflow) increments
|
|
18
|
+
* `frontmcp_skills_audit_dropped_total{reason}`. Left as a callback so the
|
|
19
|
+
* audit module doesn't take a metrics dependency.
|
|
20
|
+
*/
|
|
21
|
+
export interface SkillAuditMetrics {
|
|
22
|
+
incrementWriteFailure(reason: 'sign' | 'append' | 'unexpected'): void;
|
|
23
|
+
incrementDropped?(reason: 'queue-overflow' | 'background-failure'): void;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Context the tool passes to each write call. Contains everything needed
|
|
27
|
+
* to fully describe the invocation without leaking the raw input/output
|
|
28
|
+
* payloads into the audit record.
|
|
29
|
+
*/
|
|
30
|
+
export interface SkillAuditWriteContext {
|
|
31
|
+
subject: string;
|
|
32
|
+
skillId: string;
|
|
33
|
+
actionId: string;
|
|
34
|
+
bundleId: string;
|
|
35
|
+
bundleVersion: string;
|
|
36
|
+
/** Raw input — hashed via JCS before storage. Never persisted verbatim. */
|
|
37
|
+
input: unknown;
|
|
38
|
+
}
|
|
39
|
+
/** Extra fields for the http-call-success path. */
|
|
40
|
+
export interface SkillAuditSuccessExtras {
|
|
41
|
+
status: number;
|
|
42
|
+
/** Response body — hashed via JCS before storage. */
|
|
43
|
+
output: unknown;
|
|
44
|
+
}
|
|
45
|
+
/** Extra fields for the http-call-failure path. */
|
|
46
|
+
export interface SkillAuditFailureExtras {
|
|
47
|
+
status: number;
|
|
48
|
+
/** Free-form error description — truncated/redacted into `errorMessage`. */
|
|
49
|
+
error: unknown;
|
|
50
|
+
}
|
|
51
|
+
/** Extra fields for the authority-check-fail path. */
|
|
52
|
+
export interface SkillAuditAuthorityFailExtras {
|
|
53
|
+
/** Reason from the AuthorityGuard (e.g. `'roles missing: admin'`). */
|
|
54
|
+
reason: string;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Maximum length of the truncated error message persisted in the record.
|
|
58
|
+
* Picked to fit comfortably in any storage backend's value-size budget while
|
|
59
|
+
* still being long enough to identify the failure mode.
|
|
60
|
+
*/
|
|
61
|
+
export declare const SKILL_AUDIT_ERROR_MESSAGE_MAX = 500;
|
|
62
|
+
/**
|
|
63
|
+
* Maximum number of pending audit writes queued in-process. When the queue
|
|
64
|
+
* is full new writes are dropped (with a metrics increment + warn log)
|
|
65
|
+
* instead of blocking the tool. Picked to absorb a few seconds of slow-store
|
|
66
|
+
* latency at the project's expected QPS without becoming a memory landmine
|
|
67
|
+
* during sustained backend outage.
|
|
68
|
+
*/
|
|
69
|
+
export declare const SKILL_AUDIT_QUEUE_MAX = 1000;
|
|
70
|
+
/**
|
|
71
|
+
* Options accepted by {@link SkillAuditWriter}. All fields optional — sane
|
|
72
|
+
* defaults match the previous behavior except for `subjectMode`, which
|
|
73
|
+
* defaults to `'hash'` for GDPR friendliness.
|
|
74
|
+
*/
|
|
75
|
+
export interface SkillAuditWriterOptions {
|
|
76
|
+
/** See {@link SkillAuditSubjectMode}. Default: `'hash'`. */
|
|
77
|
+
subjectMode?: SkillAuditSubjectMode;
|
|
78
|
+
/**
|
|
79
|
+
* Secret used for the subject HMAC when `subjectMode: 'hash'`. Hosts
|
|
80
|
+
* SHOULD pass a stable, host-managed key (typically the same audit
|
|
81
|
+
* secret you use for HS256 signing). When omitted, a deterministic key
|
|
82
|
+
* is derived from the signer's keyId so subject hashes are stable
|
|
83
|
+
* within the process — but NOT across restarts unless the signer keyId
|
|
84
|
+
* is also stable.
|
|
85
|
+
*/
|
|
86
|
+
subjectHashSecret?: Uint8Array;
|
|
87
|
+
/** See {@link SKILL_AUDIT_QUEUE_MAX}. Default: 1000. */
|
|
88
|
+
maxQueueDepth?: number;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Audit writer service. Constructed once per scope and resolved out of DI
|
|
92
|
+
* by the ExecuteActionTool. Calls return a promise that resolves after the
|
|
93
|
+
* chained store work completes — but the tool detaches that promise so a
|
|
94
|
+
* slow audit backend never directly slows every skill invocation.
|
|
95
|
+
*/
|
|
96
|
+
export declare class SkillAuditWriter {
|
|
97
|
+
private readonly store;
|
|
98
|
+
private readonly signer;
|
|
99
|
+
private readonly logger;
|
|
100
|
+
private readonly metrics?;
|
|
101
|
+
/**
|
|
102
|
+
* Single-flight queue: every append() chains onto this promise so the
|
|
103
|
+
* read-tail-then-append-with-prevHash sequence stays atomic per process.
|
|
104
|
+
* This is the mate to the storage adapter's `incr` for cross-pod safety.
|
|
105
|
+
*/
|
|
106
|
+
private chainHeadLock;
|
|
107
|
+
/** Current in-flight queue depth (records awaiting the chain head lock). */
|
|
108
|
+
private queueDepth;
|
|
109
|
+
private readonly subjectMode;
|
|
110
|
+
private readonly subjectHashSecret;
|
|
111
|
+
private readonly maxQueueDepth;
|
|
112
|
+
constructor(store: SkillAuditStore, signer: SkillAuditSigner, logger: SkillAuditLogger, metrics?: SkillAuditMetrics | undefined, options?: SkillAuditWriterOptions);
|
|
113
|
+
/**
|
|
114
|
+
* Phase 2 in the tool: authority check just passed. We log the inputHash
|
|
115
|
+
* here so even invocations that fail at the network layer still leave a
|
|
116
|
+
* forensic breadcrumb tying the input to the policy decision.
|
|
117
|
+
*/
|
|
118
|
+
writeAuthorityPass(ctx: SkillAuditWriteContext): Promise<void>;
|
|
119
|
+
/**
|
|
120
|
+
* Phase 2 in the tool: authority check denied. Writing this record is
|
|
121
|
+
* security-relevant — without it, denied invocations would not appear in
|
|
122
|
+
* the audit log at all, and the most security-relevant events (someone
|
|
123
|
+
* trying to invoke an action they're not authorized for) would silently
|
|
124
|
+
* disappear. The tool MUST call this before returning the denial envelope.
|
|
125
|
+
*/
|
|
126
|
+
writeAuthorityFail(ctx: SkillAuditWriteContext, extras: SkillAuditAuthorityFailExtras): Promise<void>;
|
|
127
|
+
/** Phase 4 in the tool, success path. */
|
|
128
|
+
writeHttpCallSuccess(ctx: SkillAuditWriteContext, extras: SkillAuditSuccessExtras): Promise<void>;
|
|
129
|
+
/** Phase 4 in the tool, failure path. */
|
|
130
|
+
writeHttpCallFailure(ctx: SkillAuditWriteContext, extras: SkillAuditFailureExtras): Promise<void>;
|
|
131
|
+
/**
|
|
132
|
+
* Wait for all pending writes to complete. Useful for tests and graceful
|
|
133
|
+
* shutdown — the chain head lock resolves once every queued write has
|
|
134
|
+
* finished (success or swallowed-failure). Never throws.
|
|
135
|
+
*/
|
|
136
|
+
flush(): Promise<void>;
|
|
137
|
+
private write;
|
|
138
|
+
private doWrite;
|
|
139
|
+
/**
|
|
140
|
+
* Best-effort sequence rollback. Storage adapters that support `decr` will
|
|
141
|
+
* close the gap; ones that don't are no-ops. We never throw out of this
|
|
142
|
+
* helper — a failed rollback is strictly worse than a permanent gap.
|
|
143
|
+
*
|
|
144
|
+
* Detection is duck-typed (we look at `.adapter.decr` and `.options.sequenceKey`)
|
|
145
|
+
* because the SkillAuditStore interface intentionally doesn't expose
|
|
146
|
+
* sequence-mutation methods — those are storage-specific implementation
|
|
147
|
+
* detail, and forcing every implementation to expose them would push the
|
|
148
|
+
* complexity onto every adapter even when the underlying store can't
|
|
149
|
+
* support transactional rollback.
|
|
150
|
+
*/
|
|
151
|
+
private tryDecrementSequence;
|
|
152
|
+
/** Apply the configured subject-mode redaction. */
|
|
153
|
+
private applySubjectMode;
|
|
154
|
+
/**
|
|
155
|
+
* Default subject-hash secret derivation when the host doesn't supply one.
|
|
156
|
+
* Returns a deterministic 32-byte key seeded from the signer's keyId so
|
|
157
|
+
* two SkillAuditWriter instances configured against the same signer
|
|
158
|
+
* produce stable subject hashes — useful for joining records across
|
|
159
|
+
* writer reconfigurations within the same logical deployment. NOT a
|
|
160
|
+
* cryptographic key in its own right — the host SHOULD override via
|
|
161
|
+
* constructor options for production deployments.
|
|
162
|
+
*/
|
|
163
|
+
private deriveDefaultSubjectSecret;
|
|
164
|
+
/**
|
|
165
|
+
* Hash arbitrary output. Falls back to a sentinel if canonicalization
|
|
166
|
+
* fails (circular references, non-serializable values) — the verifier
|
|
167
|
+
* will treat it as a hash like any other.
|
|
168
|
+
*/
|
|
169
|
+
private safeHash;
|
|
170
|
+
/** Truncate + sanitize an error to fit in the record. */
|
|
171
|
+
private formatError;
|
|
172
|
+
}
|
|
173
|
+
/** Sentinel for the very first record's prevHash. Re-exported for ergonomics. */
|
|
174
|
+
export { SKILL_AUDIT_GENESIS_PREV_HASH };
|
|
175
|
+
//# sourceMappingURL=audit-writer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audit-writer.d.ts","sourceRoot":"","sources":["../../../src/skills/audit/audit-writer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { SKILL_AUDIT_GENESIS_PREV_HASH, SKILL_AUDIT_KEYS, type SkillAuditPhase, type SkillAuditRecord, type SkillAuditSignatureAlg, } from './audit-record.types';
|
|
2
|
+
export { canonicalizeRecordForSigning, linkRecord, nextPrevHash, verifyChain, type AuditChainVerifyResult, type AuditSignatureVerifier, type AuditTrustedKey, type SkillAuditPartialRecord, } from './audit-chain';
|
|
3
|
+
export { defaultAuditSignatureVerifier, Hs256AuditSigner, Rs256AuditSigner, type SkillAuditSignResult, type SkillAuditSigner, } from './audit-signer';
|
|
4
|
+
export { MemoryAuditStore, StorageAdapterAuditStore, type SkillAuditReadOptions, type SkillAuditStore, } from './audit-store';
|
|
5
|
+
export { SkillAuditWriter, SKILL_AUDIT_ERROR_MESSAGE_MAX, SKILL_AUDIT_QUEUE_MAX, type SkillAuditAuthorityFailExtras, type SkillAuditFailureExtras, type SkillAuditLogger, type SkillAuditMetrics, type SkillAuditSuccessExtras, type SkillAuditWriteContext, type SkillAuditWriterOptions, } from './audit-writer';
|
|
6
|
+
export { SkillAuditWriterToken, type SkillAuditConfig, type SkillAuditSubjectMode } from './audit-config';
|
|
7
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/skills/audit/index.ts"],"names":[],"mappings":"AAMA,OAAO,EACL,6BAA6B,EAC7B,gBAAgB,EAChB,KAAK,eAAe,EACpB,KAAK,gBAAgB,EACrB,KAAK,sBAAsB,GAC5B,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EACL,4BAA4B,EAC5B,UAAU,EACV,YAAY,EACZ,WAAW,EACX,KAAK,sBAAsB,EAC3B,KAAK,sBAAsB,EAC3B,KAAK,eAAe,EACpB,KAAK,uBAAuB,GAC7B,MAAM,eAAe,CAAC;AAEvB,OAAO,EACL,6BAA6B,EAC7B,gBAAgB,EAChB,gBAAgB,EAChB,KAAK,oBAAoB,EACzB,KAAK,gBAAgB,GACtB,MAAM,gBAAgB,CAAC;AAExB,OAAO,EACL,gBAAgB,EAChB,wBAAwB,EACxB,KAAK,qBAAqB,EAC1B,KAAK,eAAe,GACrB,MAAM,eAAe,CAAC;AAEvB,OAAO,EACL,gBAAgB,EAChB,6BAA6B,EAC7B,qBAAqB,EACrB,KAAK,6BAA6B,EAClC,KAAK,uBAAuB,EAC5B,KAAK,gBAAgB,EACrB,KAAK,iBAAiB,EACtB,KAAK,uBAAuB,EAC5B,KAAK,sBAAsB,EAC3B,KAAK,uBAAuB,GAC7B,MAAM,gBAAgB,CAAC;AAExB,OAAO,EAAE,qBAAqB,EAAE,KAAK,gBAAgB,EAAE,KAAK,qBAAqB,EAAE,MAAM,gBAAgB,CAAC"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { ResolvedBundle } from './bundle.types';
|
|
2
|
+
export interface BundleDiff {
|
|
3
|
+
/** Skill ids added by the new bundle (not present in old). */
|
|
4
|
+
addedSkillIds: string[];
|
|
5
|
+
/** Skill ids removed (present in old, not in new). */
|
|
6
|
+
removedSkillIds: string[];
|
|
7
|
+
/** Skill ids whose content changed (registered in both, differing fields). */
|
|
8
|
+
changedSkillIds: string[];
|
|
9
|
+
/** Operation ids added. */
|
|
10
|
+
addedOperationIds: string[];
|
|
11
|
+
/** Operation ids removed. */
|
|
12
|
+
removedOperationIds: string[];
|
|
13
|
+
/** Operation ids whose descriptor changed. */
|
|
14
|
+
changedOperationIds: string[];
|
|
15
|
+
/** True if the diff is structurally a no-op (same version + same content). */
|
|
16
|
+
isNoOp: boolean;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Compute the structural diff between two bundles.
|
|
20
|
+
*
|
|
21
|
+
* `oldBundle === undefined` means "no previous bundle" — every skill / op is
|
|
22
|
+
* treated as added. Identity is by `id` for skills and by `operationId` for ops.
|
|
23
|
+
*/
|
|
24
|
+
export declare function diffBundles(oldBundle: ResolvedBundle | undefined, newBundle: ResolvedBundle): BundleDiff;
|
|
25
|
+
/**
|
|
26
|
+
* Render a one-line audit-friendly summary of a diff.
|
|
27
|
+
* Used by the bundle-swap log line that operators tail for rug-pull detection.
|
|
28
|
+
*/
|
|
29
|
+
export declare function formatDiffSummary(diff: BundleDiff): string;
|
|
30
|
+
//# sourceMappingURL=bundle-diff.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bundle-diff.d.ts","sourceRoot":"","sources":["../../../src/skills/bundle/bundle-diff.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAuB,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAE1E,MAAM,WAAW,UAAU;IACzB,8DAA8D;IAC9D,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,sDAAsD;IACtD,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,8EAA8E;IAC9E,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,2BAA2B;IAC3B,iBAAiB,EAAE,MAAM,EAAE,CAAC;IAC5B,6BAA6B;IAC7B,mBAAmB,EAAE,MAAM,EAAE,CAAC;IAC9B,8CAA8C;IAC9C,mBAAmB,EAAE,MAAM,EAAE,CAAC;IAC9B,8EAA8E;IAC9E,MAAM,EAAE,OAAO,CAAC;CACjB;AAwBD;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,SAAS,EAAE,cAAc,GAAG,SAAS,EAAE,SAAS,EAAE,cAAc,GAAG,UAAU,CAoDxG;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,CAM1D"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { z } from '@frontmcp/lazy-zod';
|
|
2
|
+
export declare const resolvedBundleSchema: import("@frontmcp/lazy-zod").ZodObject<{
|
|
3
|
+
schemaVersion: import("@frontmcp/lazy-zod").ZodLiteral<1>;
|
|
4
|
+
bundleId: import("@frontmcp/lazy-zod").ZodString;
|
|
5
|
+
version: import("@frontmcp/lazy-zod").ZodString;
|
|
6
|
+
generatedAt: import("@frontmcp/lazy-zod").ZodString;
|
|
7
|
+
sourceDigest: import("@frontmcp/lazy-zod").ZodString;
|
|
8
|
+
services: import("@frontmcp/lazy-zod").ZodArray<import("@frontmcp/lazy-zod").ZodObject<{
|
|
9
|
+
id: import("@frontmcp/lazy-zod").ZodString;
|
|
10
|
+
baseUrl: import("@frontmcp/lazy-zod").ZodString;
|
|
11
|
+
description: import("@frontmcp/lazy-zod").ZodOptional<import("@frontmcp/lazy-zod").ZodString>;
|
|
12
|
+
}, import("zod/v4/core").$strict>>;
|
|
13
|
+
authBindings: import("@frontmcp/lazy-zod").ZodRecord<import("@frontmcp/lazy-zod").ZodString, import("@frontmcp/lazy-zod").ZodDiscriminatedUnion<[import("@frontmcp/lazy-zod").ZodObject<{
|
|
14
|
+
kind: import("@frontmcp/lazy-zod").ZodLiteral<"none">;
|
|
15
|
+
}, import("zod/v4/core").$strict>, import("@frontmcp/lazy-zod").ZodObject<{
|
|
16
|
+
kind: import("@frontmcp/lazy-zod").ZodLiteral<"bearer">;
|
|
17
|
+
vaultRef: import("@frontmcp/lazy-zod").ZodString;
|
|
18
|
+
passthroughCallerToken: import("@frontmcp/lazy-zod").ZodOptional<import("@frontmcp/lazy-zod").ZodBoolean>;
|
|
19
|
+
}, import("zod/v4/core").$strict>, import("@frontmcp/lazy-zod").ZodObject<{
|
|
20
|
+
kind: import("@frontmcp/lazy-zod").ZodLiteral<"apiKey">;
|
|
21
|
+
in: import("@frontmcp/lazy-zod").ZodEnum<{
|
|
22
|
+
query: "query";
|
|
23
|
+
header: "header";
|
|
24
|
+
}>;
|
|
25
|
+
name: import("@frontmcp/lazy-zod").ZodString;
|
|
26
|
+
vaultRef: import("@frontmcp/lazy-zod").ZodString;
|
|
27
|
+
}, import("zod/v4/core").$strict>, import("@frontmcp/lazy-zod").ZodObject<{
|
|
28
|
+
kind: import("@frontmcp/lazy-zod").ZodLiteral<"oauth2">;
|
|
29
|
+
flow: import("@frontmcp/lazy-zod").ZodLiteral<"client_credentials">;
|
|
30
|
+
vaultRef: import("@frontmcp/lazy-zod").ZodString;
|
|
31
|
+
}, import("zod/v4/core").$strict>], "kind">>;
|
|
32
|
+
skills: import("@frontmcp/lazy-zod").ZodArray<import("@frontmcp/lazy-zod").ZodObject<{
|
|
33
|
+
id: import("@frontmcp/lazy-zod").ZodString;
|
|
34
|
+
name: import("@frontmcp/lazy-zod").ZodString;
|
|
35
|
+
description: import("@frontmcp/lazy-zod").ZodString;
|
|
36
|
+
instructions: import("@frontmcp/lazy-zod").ZodString;
|
|
37
|
+
tags: import("@frontmcp/lazy-zod").ZodOptional<import("@frontmcp/lazy-zod").ZodArray<import("@frontmcp/lazy-zod").ZodString>>;
|
|
38
|
+
operationIds: import("@frontmcp/lazy-zod").ZodArray<import("@frontmcp/lazy-zod").ZodString>;
|
|
39
|
+
requiredAuthorities: import("@frontmcp/lazy-zod").ZodOptional<import("@frontmcp/lazy-zod").ZodRecord<import("@frontmcp/lazy-zod").ZodString, import("@frontmcp/lazy-zod").ZodUnknown>>;
|
|
40
|
+
requires: import("@frontmcp/lazy-zod").ZodOptional<import("@frontmcp/lazy-zod").ZodArray<import("@frontmcp/lazy-zod").ZodString>>;
|
|
41
|
+
}, import("zod/v4/core").$strict>>;
|
|
42
|
+
operations: import("@frontmcp/lazy-zod").ZodRecord<import("@frontmcp/lazy-zod").ZodString, import("@frontmcp/lazy-zod").ZodObject<{
|
|
43
|
+
operationId: import("@frontmcp/lazy-zod").ZodString;
|
|
44
|
+
serviceId: import("@frontmcp/lazy-zod").ZodString;
|
|
45
|
+
httpMethod: import("@frontmcp/lazy-zod").ZodEnum<{
|
|
46
|
+
GET: "GET";
|
|
47
|
+
POST: "POST";
|
|
48
|
+
PUT: "PUT";
|
|
49
|
+
PATCH: "PATCH";
|
|
50
|
+
DELETE: "DELETE";
|
|
51
|
+
HEAD: "HEAD";
|
|
52
|
+
}>;
|
|
53
|
+
pathTemplate: import("@frontmcp/lazy-zod").ZodString;
|
|
54
|
+
inputSchema: import("@frontmcp/lazy-zod").ZodRecord<import("@frontmcp/lazy-zod").ZodString, import("@frontmcp/lazy-zod").ZodUnknown>;
|
|
55
|
+
outputSchema: import("@frontmcp/lazy-zod").ZodRecord<import("@frontmcp/lazy-zod").ZodString, import("@frontmcp/lazy-zod").ZodUnknown>;
|
|
56
|
+
mapper: import("@frontmcp/lazy-zod").ZodArray<import("@frontmcp/lazy-zod").ZodObject<{
|
|
57
|
+
inputKey: import("@frontmcp/lazy-zod").ZodString;
|
|
58
|
+
type: import("@frontmcp/lazy-zod").ZodEnum<{
|
|
59
|
+
query: "query";
|
|
60
|
+
cookie: "cookie";
|
|
61
|
+
path: "path";
|
|
62
|
+
header: "header";
|
|
63
|
+
body: "body";
|
|
64
|
+
}>;
|
|
65
|
+
key: import("@frontmcp/lazy-zod").ZodString;
|
|
66
|
+
required: import("@frontmcp/lazy-zod").ZodOptional<import("@frontmcp/lazy-zod").ZodBoolean>;
|
|
67
|
+
style: import("@frontmcp/lazy-zod").ZodOptional<import("@frontmcp/lazy-zod").ZodString>;
|
|
68
|
+
explode: import("@frontmcp/lazy-zod").ZodOptional<import("@frontmcp/lazy-zod").ZodBoolean>;
|
|
69
|
+
serialization: import("@frontmcp/lazy-zod").ZodOptional<import("@frontmcp/lazy-zod").ZodRecord<import("@frontmcp/lazy-zod").ZodString, import("@frontmcp/lazy-zod").ZodUnknown>>;
|
|
70
|
+
security: import("@frontmcp/lazy-zod").ZodOptional<import("@frontmcp/lazy-zod").ZodRecord<import("@frontmcp/lazy-zod").ZodString, import("@frontmcp/lazy-zod").ZodUnknown>>;
|
|
71
|
+
}, import("zod/v4/core").$loose>>;
|
|
72
|
+
authBindingRef: import("@frontmcp/lazy-zod").ZodString;
|
|
73
|
+
requiredAuthorities: import("@frontmcp/lazy-zod").ZodOptional<import("@frontmcp/lazy-zod").ZodRecord<import("@frontmcp/lazy-zod").ZodString, import("@frontmcp/lazy-zod").ZodUnknown>>;
|
|
74
|
+
maxResponseBytes: import("@frontmcp/lazy-zod").ZodOptional<import("@frontmcp/lazy-zod").ZodNumber>;
|
|
75
|
+
timeoutMs: import("@frontmcp/lazy-zod").ZodOptional<import("@frontmcp/lazy-zod").ZodNumber>;
|
|
76
|
+
summary: import("@frontmcp/lazy-zod").ZodOptional<import("@frontmcp/lazy-zod").ZodString>;
|
|
77
|
+
description: import("@frontmcp/lazy-zod").ZodOptional<import("@frontmcp/lazy-zod").ZodString>;
|
|
78
|
+
}, import("zod/v4/core").$strict>>;
|
|
79
|
+
integrity: import("@frontmcp/lazy-zod").ZodOptional<import("@frontmcp/lazy-zod").ZodObject<{
|
|
80
|
+
alg: import("@frontmcp/lazy-zod").ZodEnum<{
|
|
81
|
+
RS256: "RS256";
|
|
82
|
+
EdDSA: "EdDSA";
|
|
83
|
+
}>;
|
|
84
|
+
keyId: import("@frontmcp/lazy-zod").ZodString;
|
|
85
|
+
signature: import("@frontmcp/lazy-zod").ZodString;
|
|
86
|
+
digest: import("@frontmcp/lazy-zod").ZodString;
|
|
87
|
+
}, import("zod/v4/core").$strict>>;
|
|
88
|
+
}, import("zod/v4/core").$strict>;
|
|
89
|
+
export type ParsedBundle = z.infer<typeof resolvedBundleSchema>;
|
|
90
|
+
/**
|
|
91
|
+
* Cross-field validation: every operation's serviceId must reference a known
|
|
92
|
+
* service, every operation's authBindingRef must reference a known binding,
|
|
93
|
+
* every skill's operationIds must reference known operations.
|
|
94
|
+
*/
|
|
95
|
+
export declare function crossValidate(bundle: ParsedBundle): {
|
|
96
|
+
ok: true;
|
|
97
|
+
} | {
|
|
98
|
+
ok: false;
|
|
99
|
+
errors: string[];
|
|
100
|
+
};
|
|
101
|
+
//# sourceMappingURL=bundle.schema.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bundle.schema.d.ts","sourceRoot":"","sources":["../../../src/skills/bundle/bundle.schema.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,CAAC,EAAE,MAAM,oBAAoB,CAAC;AA8IvC,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iCAwBtB,CAAC;AAEZ,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAEhE;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,YAAY,GAAG;IAAE,EAAE,EAAE,IAAI,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,EAAE,CAAA;CAAE,CAgClG"}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { type BundleDiff } from './bundle-diff';
|
|
2
|
+
import type { ResolvedBundle } from './bundle.types';
|
|
3
|
+
export type BundleSwapListener = (event: {
|
|
4
|
+
previous: ResolvedBundle | undefined;
|
|
5
|
+
current: ResolvedBundle;
|
|
6
|
+
diff: BundleDiff;
|
|
7
|
+
/** Marker that the swap was triggered by `pin(version)` or `rollback()`. */
|
|
8
|
+
reason?: 'normal' | 'pin' | 'rollback';
|
|
9
|
+
}) => void;
|
|
10
|
+
/**
|
|
11
|
+
* Minimal telemetry surface the BundleStore needs. Modeled to be a structural
|
|
12
|
+
* subset of `@frontmcp/observability`'s `TelemetryAccessor` so callers can
|
|
13
|
+
* pass that directly, but defined here to keep `@frontmcp/adapters` from
|
|
14
|
+
* picking up a hard dependency on the observability package.
|
|
15
|
+
*/
|
|
16
|
+
export interface BundleStoreCounter {
|
|
17
|
+
inc(by?: number, attributes?: Record<string, string>): void;
|
|
18
|
+
}
|
|
19
|
+
export interface BundleStoreSpan {
|
|
20
|
+
setAttributes(attrs: Record<string, string | number | boolean>): void;
|
|
21
|
+
addEvent(name: string, attrs?: Record<string, string | number | boolean>): void;
|
|
22
|
+
recordError?(error: Error): void;
|
|
23
|
+
end(): void;
|
|
24
|
+
endWithError?(error: Error | string): void;
|
|
25
|
+
}
|
|
26
|
+
export interface BundleStoreTelemetry {
|
|
27
|
+
/** Create (or fetch cached) named counter, e.g. `frontmcp_skills_bundle_pulls_total`. */
|
|
28
|
+
createCounter(name: string, description?: string): BundleStoreCounter;
|
|
29
|
+
/**
|
|
30
|
+
* Start a span. Caller is responsible for `end()` / `endWithError()`.
|
|
31
|
+
* Synchronous — matches the current sync semantics of `swap()`.
|
|
32
|
+
*/
|
|
33
|
+
startSpan(name: string, attributes?: Record<string, string | number | boolean>): BundleStoreSpan;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Options that control the store's history ring buffer and pin behavior.
|
|
37
|
+
*/
|
|
38
|
+
export interface BundleStoreOptions {
|
|
39
|
+
/**
|
|
40
|
+
* Number of past bundles to retain in memory (in addition to the active one).
|
|
41
|
+
* Used by `pin(version)` and `rollback()`. Default: 3. Must be >= 1.
|
|
42
|
+
*/
|
|
43
|
+
historySize?: number;
|
|
44
|
+
/**
|
|
45
|
+
* Optional telemetry hook. When provided, `swap()` is wrapped in a
|
|
46
|
+
* `skill.bundle.swap` span and the bundle-pulls counter is incremented
|
|
47
|
+
* with `{ status, source, reason? }` attributes. When omitted, the store
|
|
48
|
+
* emits no telemetry (zero overhead — no span, no counter).
|
|
49
|
+
*/
|
|
50
|
+
telemetry?: BundleStoreTelemetry;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* In-memory holder for the active bundle plus a small history ring buffer.
|
|
54
|
+
*
|
|
55
|
+
* Atomic swap semantics: `swap()` either fully transitions to the new bundle
|
|
56
|
+
* (and returns the diff) or throws and leaves the previous bundle untouched.
|
|
57
|
+
*
|
|
58
|
+
* Versioning + rollback (v1.2):
|
|
59
|
+
* - Every successful `swap()` pushes the prior bundle into a fixed-size
|
|
60
|
+
* history ring (`historySize`). The ring stores entries by version so
|
|
61
|
+
* `pin(version)` can re-activate any of the last N bundles.
|
|
62
|
+
* - `pin(version)` snaps the active bundle to a previously-known version,
|
|
63
|
+
* refuses if the version isn't in history, and marks the store pinned.
|
|
64
|
+
* - While pinned, `swap()` is rejected (caller decides whether to log/skip
|
|
65
|
+
* or throw); the existing source listeners keep running so the host
|
|
66
|
+
* observes new versions arriving but never auto-applies them.
|
|
67
|
+
* - `rollback()` is sugar for `pin(previousActiveVersion)`.
|
|
68
|
+
*
|
|
69
|
+
* Listeners run synchronously after a successful swap/pin/rollback — keep
|
|
70
|
+
* them cheap.
|
|
71
|
+
*/
|
|
72
|
+
export declare class BundleStore {
|
|
73
|
+
private active;
|
|
74
|
+
private listeners;
|
|
75
|
+
private history;
|
|
76
|
+
private pinnedVersion;
|
|
77
|
+
private readonly historySize;
|
|
78
|
+
private readonly telemetry;
|
|
79
|
+
private readonly pullsCounter;
|
|
80
|
+
constructor(options?: BundleStoreOptions);
|
|
81
|
+
current(): ResolvedBundle | undefined;
|
|
82
|
+
/**
|
|
83
|
+
* Swap to a new bundle. Returns the structural diff (no-op = same version
|
|
84
|
+
* with no field changes; the swap itself still fires listeners with isNoOp=true
|
|
85
|
+
* so observers can record the heartbeat).
|
|
86
|
+
*
|
|
87
|
+
* Throws when the store is pinned. The caller should check `isPinned()` first
|
|
88
|
+
* if it wants to skip silently rather than throw.
|
|
89
|
+
*
|
|
90
|
+
* @param next - new bundle to activate
|
|
91
|
+
* @param source - optional source label (e.g. `npm`, `saas-pull`, `webhook`)
|
|
92
|
+
* used as a counter / span attribute. When omitted, `unknown`
|
|
93
|
+
* is reported.
|
|
94
|
+
*/
|
|
95
|
+
swap(next: ResolvedBundle, source?: string): BundleDiff;
|
|
96
|
+
/**
|
|
97
|
+
* Pin the active bundle to a specific historical version. Pinned stores
|
|
98
|
+
* reject `swap()` so source-driven updates accumulate elsewhere without
|
|
99
|
+
* activating. Returns the diff of the swap that activated the pinned
|
|
100
|
+
* version, or undefined if the pinned version was already active.
|
|
101
|
+
*
|
|
102
|
+
* Throws when `version` is unknown to the store's history.
|
|
103
|
+
*/
|
|
104
|
+
pin(version: string): BundleDiff | undefined;
|
|
105
|
+
/**
|
|
106
|
+
* Re-activate the most recent bundle in history (the bundle that was
|
|
107
|
+
* active before the current one). Useful after a bad swap is detected.
|
|
108
|
+
* Returns the diff. Throws when no prior bundle is available.
|
|
109
|
+
*
|
|
110
|
+
* Rollback does NOT pin — sources can resume auto-swapping after rollback.
|
|
111
|
+
*/
|
|
112
|
+
rollback(): BundleDiff;
|
|
113
|
+
/** Lift the pin so `swap()` accepts new bundles again. */
|
|
114
|
+
unpin(): void;
|
|
115
|
+
/** True when the store is currently pinned. */
|
|
116
|
+
isPinned(): boolean;
|
|
117
|
+
/** Pinned version string, or undefined when unpinned. */
|
|
118
|
+
pinned(): string | undefined;
|
|
119
|
+
/**
|
|
120
|
+
* Snapshot of the history ring (oldest first; does not include the active
|
|
121
|
+
* bundle). Returned array is a shallow copy — safe to inspect.
|
|
122
|
+
*/
|
|
123
|
+
historySnapshot(): {
|
|
124
|
+
version: string;
|
|
125
|
+
bundleId: string;
|
|
126
|
+
validatedAt: number;
|
|
127
|
+
}[];
|
|
128
|
+
/** Subscribe to swap events. Returns an unsubscribe function. */
|
|
129
|
+
subscribe(fn: BundleSwapListener): () => void;
|
|
130
|
+
/** Reset to empty state. Used by tests. Does NOT fire listeners. */
|
|
131
|
+
reset(): void;
|
|
132
|
+
/** Commit a new active bundle (shared by swap / pin / rollback). */
|
|
133
|
+
private commit;
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Thrown by `BundleStore.swap()` when the store is pinned. Callers that prefer
|
|
137
|
+
* to skip silently should check `isPinned()` before calling swap.
|
|
138
|
+
*/
|
|
139
|
+
export declare class BundlePinnedError extends Error {
|
|
140
|
+
readonly pinnedVersion: string;
|
|
141
|
+
constructor(pinnedVersion: string);
|
|
142
|
+
}
|
|
143
|
+
//# sourceMappingURL=bundle.store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bundle.store.d.ts","sourceRoot":"","sources":["../../../src/skills/bundle/bundle.store.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import type { SkillAction } from '@frontmcp/sdk';
|
|
2
|
+
import type { ParameterMapper } from '../../openapi';
|
|
3
|
+
/** HTTP methods we accept in v1.2. Multipart, SSE, websockets are out of scope. */
|
|
4
|
+
export type HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'HEAD';
|
|
5
|
+
/** ABAC/RBAC policy carried by skills/ops. Loose at the boundary; libs/auth interprets. */
|
|
6
|
+
export type AuthoritiesPolicy = Record<string, unknown>;
|
|
7
|
+
/** Auth binding that the executor resolves to a real credential at call time. */
|
|
8
|
+
export type AuthBinding = {
|
|
9
|
+
kind: 'none';
|
|
10
|
+
} | {
|
|
11
|
+
kind: 'bearer';
|
|
12
|
+
vaultRef: string;
|
|
13
|
+
passthroughCallerToken?: boolean;
|
|
14
|
+
} | {
|
|
15
|
+
kind: 'apiKey';
|
|
16
|
+
in: 'header' | 'query';
|
|
17
|
+
name: string;
|
|
18
|
+
vaultRef: string;
|
|
19
|
+
} | {
|
|
20
|
+
kind: 'oauth2';
|
|
21
|
+
flow: 'client_credentials';
|
|
22
|
+
vaultRef: string;
|
|
23
|
+
};
|
|
24
|
+
/** Service descriptor — one per microservice referenced by the bundle. */
|
|
25
|
+
export interface ServiceDescriptor {
|
|
26
|
+
/** Stable id (e.g. "billing"). Referenced by `OperationDescriptor.serviceId`. */
|
|
27
|
+
id: string;
|
|
28
|
+
/** Resolved server URL (no trailing slash). */
|
|
29
|
+
baseUrl: string;
|
|
30
|
+
/** Optional human-readable description. */
|
|
31
|
+
description?: string;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* One executable operation derived from an OpenAPI `operationId`. The MCP client
|
|
35
|
+
* never sees these directly — they are invokable only through the plugin's
|
|
36
|
+
* `execute_action` meta-tool, which resolves `(skillId, actionId)` to one of these.
|
|
37
|
+
*
|
|
38
|
+
* The descriptor is shaped so it can be projected onto an `McpOpenAPITool` for
|
|
39
|
+
* reuse of `@frontmcp/adapters/openapi`'s `buildRequest` / `parseResponse`
|
|
40
|
+
* runtime helpers — the SaaS analyzer ships the `mapper` array so the plugin
|
|
41
|
+
* doesn't need to re-derive parameter locations from a raw OpenAPI spec.
|
|
42
|
+
*/
|
|
43
|
+
export interface OperationDescriptor {
|
|
44
|
+
/** Stable identifier within the bundle (matches OpenAPI operationId). */
|
|
45
|
+
operationId: string;
|
|
46
|
+
/** Service this op lives in. Must match a `ServiceDescriptor.id`. */
|
|
47
|
+
serviceId: string;
|
|
48
|
+
/** HTTP method. */
|
|
49
|
+
httpMethod: HttpMethod;
|
|
50
|
+
/** Path template, e.g. "/v1/customers/{id}/invoices". */
|
|
51
|
+
pathTemplate: string;
|
|
52
|
+
/**
|
|
53
|
+
* JSON Schema (Draft 2020-12) for the action's input — flat key/value map
|
|
54
|
+
* matching the inputs that `mapper[].inputKey` references.
|
|
55
|
+
*/
|
|
56
|
+
inputSchema: Record<string, unknown>;
|
|
57
|
+
/** JSON Schema for the response body. */
|
|
58
|
+
outputSchema: Record<string, unknown>;
|
|
59
|
+
/**
|
|
60
|
+
* Parameter mapper produced by the SaaS analyzer at OpenAPI parse time —
|
|
61
|
+
* tells the executor which input keys land in path / query / header / cookie /
|
|
62
|
+
* body slots. Reused verbatim by `@frontmcp/adapters/openapi`'s buildRequest.
|
|
63
|
+
*/
|
|
64
|
+
mapper: ParameterMapper[];
|
|
65
|
+
/** AuthBinding key (`bundle.authBindings[ref]`). */
|
|
66
|
+
authBindingRef: string;
|
|
67
|
+
/** Optional ABAC policy required to invoke this op. */
|
|
68
|
+
requiredAuthorities?: AuthoritiesPolicy;
|
|
69
|
+
/** Optional override of the response cap (bytes). */
|
|
70
|
+
maxResponseBytes?: number;
|
|
71
|
+
/** Optional override of the per-op timeout (ms). */
|
|
72
|
+
timeoutMs?: number;
|
|
73
|
+
/** Human-readable summary surfaced in `load_skill` content. */
|
|
74
|
+
summary?: string;
|
|
75
|
+
description?: string;
|
|
76
|
+
}
|
|
77
|
+
/** A skill bundles a curated set of operations. */
|
|
78
|
+
export interface BundledSkill {
|
|
79
|
+
/** Stable skill id (must be unique within the bundle). */
|
|
80
|
+
id: string;
|
|
81
|
+
/** Display name for the skill. */
|
|
82
|
+
name: string;
|
|
83
|
+
/** Short description. */
|
|
84
|
+
description: string;
|
|
85
|
+
/** Markdown instructions surfaced by `load_skill`. */
|
|
86
|
+
instructions: string;
|
|
87
|
+
/** Optional tags for filtering. */
|
|
88
|
+
tags?: string[];
|
|
89
|
+
/** Operation ids this skill exposes (must exist in `bundle.operations`). */
|
|
90
|
+
operationIds: string[];
|
|
91
|
+
/** Optional skill-level authorities (in addition to per-op). */
|
|
92
|
+
requiredAuthorities?: AuthoritiesPolicy;
|
|
93
|
+
/**
|
|
94
|
+
* Other skill ids this skill depends on. Same field name as the
|
|
95
|
+
* agentskills Skill Package Manifest. Resolved at apply time via
|
|
96
|
+
* `resolveSkillLoadOrder` (libs/adapters/src/skills/dependency).
|
|
97
|
+
*/
|
|
98
|
+
requires?: string[];
|
|
99
|
+
}
|
|
100
|
+
/** Detached signature envelope for the bundle. */
|
|
101
|
+
export interface BundleIntegrity {
|
|
102
|
+
alg: 'RS256' | 'EdDSA';
|
|
103
|
+
/** Stable id of the signing key, matched against `trustedKeys[].keyId`. */
|
|
104
|
+
keyId: string;
|
|
105
|
+
/** Base64url-encoded detached signature. */
|
|
106
|
+
signature: string;
|
|
107
|
+
/** Base64url-encoded canonical-bytes hash that was signed (sha256). */
|
|
108
|
+
digest: string;
|
|
109
|
+
}
|
|
110
|
+
/** A fully-resolved, validated bundle ready to project into the registry. */
|
|
111
|
+
export interface ResolvedBundle {
|
|
112
|
+
/** Wire-format version (currently 1). */
|
|
113
|
+
schemaVersion: 1;
|
|
114
|
+
/** Stable bundle identifier (customer slug + env). */
|
|
115
|
+
bundleId: string;
|
|
116
|
+
/** Monotonic version string used by clients to detect bundle swaps. */
|
|
117
|
+
version: string;
|
|
118
|
+
/** ISO timestamp the SaaS produced this bundle. */
|
|
119
|
+
generatedAt: string;
|
|
120
|
+
/** sha256 of the canonical OpenAPI source spec. */
|
|
121
|
+
sourceDigest: string;
|
|
122
|
+
/** All services this bundle covers. */
|
|
123
|
+
services: ServiceDescriptor[];
|
|
124
|
+
/** Reusable auth bindings keyed by ref string. */
|
|
125
|
+
authBindings: Record<string, AuthBinding>;
|
|
126
|
+
/** Skills declared by the bundle. */
|
|
127
|
+
skills: BundledSkill[];
|
|
128
|
+
/** All operations referenced by skills, keyed by `operationId`. */
|
|
129
|
+
operations: Record<string, OperationDescriptor>;
|
|
130
|
+
/** Optional integrity envelope. Required when plugin's requireSignature=true. */
|
|
131
|
+
integrity?: BundleIntegrity;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Convenience projection of a single skill's executable actions.
|
|
135
|
+
*
|
|
136
|
+
* Throws if any of the skill's `operationIds` is missing from `ops`. Silently
|
|
137
|
+
* dropping unknown ids would let a malformed bundle apply with the skill's
|
|
138
|
+
* advertised action list out of sync with what `execute_action` can actually
|
|
139
|
+
* resolve, so the bundle apply path treats this as a hard failure that trips
|
|
140
|
+
* the rollback.
|
|
141
|
+
*/
|
|
142
|
+
export declare function bundleSkillToActions(skill: BundledSkill, ops: Record<string, OperationDescriptor>): SkillAction[];
|
|
143
|
+
//# sourceMappingURL=bundle.types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bundle.types.d.ts","sourceRoot":"","sources":["../../../src/skills/bundle/bundle.types.ts"],"names":[],"mappings":"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"}
|