@zhama/tego-plugin-sdk 0.0.0-stage → 1.36.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +172 -0
- package/README.md +846 -2
- package/access-catalog.schema.json +304 -0
- package/access-fixtures/resolve.json +1359 -0
- package/bin/tego-plugin-pack.mjs +2 -0
- package/bin/tego-plugin.mjs +3 -0
- package/dist/access-drizzle.cjs +1 -0
- package/dist/access-drizzle.d.cts +726 -0
- package/dist/access-drizzle.d.ts +726 -0
- package/dist/access-drizzle.js +1 -0
- package/dist/access-hono.cjs +3 -0
- package/dist/access-hono.d.cts +108 -0
- package/dist/access-hono.d.ts +108 -0
- package/dist/access-hono.js +3 -0
- package/dist/access-implications.cjs +1 -0
- package/dist/access-implications.d.cts +25 -0
- package/dist/access-implications.d.ts +25 -0
- package/dist/access-implications.js +1 -0
- package/dist/access.cjs +26 -0
- package/dist/access.d.cts +884 -0
- package/dist/access.d.ts +884 -0
- package/dist/access.js +26 -0
- package/dist/catalog-CSSbrfEf.d.cts +361 -0
- package/dist/catalog-CSSbrfEf.d.ts +361 -0
- package/dist/chunk-3KUOBGJN.js +19 -0
- package/dist/chunk-3WA3M347.cjs +1 -0
- package/dist/chunk-5CU33JVY.js +1 -0
- package/dist/chunk-7K37PVGV.js +5 -0
- package/dist/chunk-7XHF3YSK.js +1 -0
- package/dist/chunk-AJY7ZHXK.cjs +3 -0
- package/dist/chunk-BN6TGHSB.cjs +1 -0
- package/dist/chunk-BTHXQWHT.js +1 -0
- package/dist/chunk-C2OCOPZQ.cjs +1 -0
- package/dist/chunk-IMAVYQ4U.cjs +4 -0
- package/dist/chunk-OP64Y4IN.cjs +1 -0
- package/dist/chunk-QKSPPMVN.js +1 -0
- package/dist/chunk-ROFUQLOZ.cjs +1 -0
- package/dist/chunk-SNUCO2MK.js +1 -0
- package/dist/chunk-THMWRUAT.cjs +19 -0
- package/dist/chunk-VMCGDDGP.js +3 -0
- package/dist/chunk-W7C357A6.cjs +5 -0
- package/dist/chunk-WLTASJF6.js +4 -0
- package/dist/egress.cjs +7 -0
- package/dist/egress.d.cts +9 -0
- package/dist/egress.d.ts +9 -0
- package/dist/egress.js +7 -0
- package/dist/frontend.cjs +2 -0
- package/dist/frontend.d.cts +353 -0
- package/dist/frontend.d.ts +353 -0
- package/dist/frontend.js +2 -0
- package/dist/gateway-signature.cjs +1 -0
- package/dist/gateway-signature.d.cts +112 -0
- package/dist/gateway-signature.d.ts +112 -0
- package/dist/gateway-signature.js +1 -0
- package/dist/index.cjs +1 -0
- package/dist/index.d.cts +528 -0
- package/dist/index.d.ts +528 -0
- package/dist/index.js +1 -0
- package/dist/manifest-types-DQARCQJt.d.cts +627 -0
- package/dist/manifest-types-DQARCQJt.d.ts +627 -0
- package/dist/manifest.cjs +1 -0
- package/dist/manifest.d.cts +2824 -0
- package/dist/manifest.d.ts +2824 -0
- package/dist/manifest.js +1 -0
- package/dist/mcp-identity.cjs +2 -0
- package/dist/mcp-identity.d.cts +106 -0
- package/dist/mcp-identity.d.ts +106 -0
- package/dist/mcp-identity.js +2 -0
- package/dist/pack.cjs +1 -0
- package/dist/pack.d.cts +169 -0
- package/dist/pack.d.ts +169 -0
- package/dist/pack.js +1 -0
- package/dist/publish.cjs +1 -0
- package/dist/publish.d.cts +96 -0
- package/dist/publish.d.ts +96 -0
- package/dist/publish.js +1 -0
- package/dist/scaffold.cjs +523 -0
- package/dist/scaffold.d.cts +182 -0
- package/dist/scaffold.d.ts +182 -0
- package/dist/scaffold.js +523 -0
- package/dist/server-runtime.cjs +1 -0
- package/dist/server-runtime.d.cts +63 -0
- package/dist/server-runtime.d.ts +63 -0
- package/dist/server-runtime.js +1 -0
- package/dist/server.cjs +1 -0
- package/dist/server.d.cts +1808 -0
- package/dist/server.d.ts +1808 -0
- package/dist/server.js +1 -0
- package/dist/testing.cjs +2 -0
- package/dist/testing.d.cts +92 -0
- package/dist/testing.d.ts +92 -0
- package/dist/testing.js +2 -0
- package/dist/vite.cjs +1 -0
- package/dist/vite.d.cts +133 -0
- package/dist/vite.d.ts +133 -0
- package/dist/vite.js +1 -0
- package/package.json +160 -4
- package/sql/access.sql +73 -0
package/dist/manifest.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export{PYTHON_LOCK_FILENAME,PYTHON_RUNNER_VERSION,PYTHON_WHEELS_DIR,checkPluginAccessCatalog,checkPythonVendoring,normalizePackageName,parseRequirementsLock,parseTegoPluginManifest,parseWheelFilename,tegoPluginManifestSchema}from"./chunk-5CU33JVY.js";import"./chunk-BTHXQWHT.js";import"./chunk-7XHF3YSK.js";import"./chunk-VMCGDDGP.js";import"./chunk-SNUCO2MK.js";
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";var p=Object.defineProperty;var a=(e,r)=>p(e,"name",{value:r,configurable:!0});var crypto=require("crypto"),MCP_IDENTITY_VERSION="1",MCP_IDENTITY_MESSAGE_PREFIX="tego-mcp-identity-v1",MCP_IDENTITY_MAX_SKEW_MS=300*1e3,MCP_IDENTITY_HEADERS={version:"x-tego-identity-version",serverId:"x-tego-identity-server-id",keyVersion:"x-tego-identity-key-version",userId:"x-tego-identity-user-id",tenantId:"x-tego-identity-tenant-id",avatarId:"x-tego-identity-avatar-id",email:"x-tego-identity-email",roles:"x-tego-identity-roles",requestId:"x-tego-identity-request-id",issuedAt:"x-tego-identity-issued-at",signature:"x-tego-identity-signature"},MCP_IDENTITY_HEADER_PREFIX="x-tego-identity-";function sha256Hex(e=""){return crypto.createHash("sha256").update(e).digest("hex")}a(sha256Hex,"sha256Hex");function canonicalMessage(e,r){const t=[MCP_IDENTITY_MESSAGE_PREFIX,e.serverId,e.keyVersion,r.method.toUpperCase(),r.pathAndQuery,r.bodySha256,e.userId,e.tenantId,e.avatarId,e.email,e.rolesHeader,e.requestId,e.issuedAt];if(t.some(s=>/[\r\n]/.test(s)))throw new Error("MCP identity fields must not contain line breaks");return t.join(`
|
|
2
|
+
`)}a(canonicalMessage,"canonicalMessage");function signMcpIdentity(e,r,t){return crypto.createHmac("sha256",t).update(canonicalMessage(e,r)).digest("hex")}a(signMcpIdentity,"signMcpIdentity");function buildMcpIdentityHeaders(e,r,t){return{[MCP_IDENTITY_HEADERS.version]:MCP_IDENTITY_VERSION,[MCP_IDENTITY_HEADERS.serverId]:e.serverId,[MCP_IDENTITY_HEADERS.keyVersion]:e.keyVersion,[MCP_IDENTITY_HEADERS.userId]:e.userId,[MCP_IDENTITY_HEADERS.tenantId]:e.tenantId,[MCP_IDENTITY_HEADERS.avatarId]:e.avatarId,[MCP_IDENTITY_HEADERS.email]:e.email,[MCP_IDENTITY_HEADERS.roles]:e.rolesHeader,[MCP_IDENTITY_HEADERS.requestId]:e.requestId,[MCP_IDENTITY_HEADERS.issuedAt]:e.issuedAt,[MCP_IDENTITY_HEADERS.signature]:signMcpIdentity(e,r,t)}}a(buildMcpIdentityHeaders,"buildMcpIdentityHeaders");function readHeader(e,r){if(typeof e.get=="function")return e.get(r)??void 0;const t=e,s=t[r]??Object.entries(t).find(([i])=>i.toLowerCase()===r)?.[1];return Array.isArray(s)?s[0]:s}a(readHeader,"readHeader");function verifyMcpIdentity(e){const r=a(v=>readHeader(e.headers,v),"read"),t={version:r(MCP_IDENTITY_HEADERS.version),serverId:r(MCP_IDENTITY_HEADERS.serverId),keyVersion:r(MCP_IDENTITY_HEADERS.keyVersion),userId:r(MCP_IDENTITY_HEADERS.userId),tenantId:r(MCP_IDENTITY_HEADERS.tenantId),avatarId:r(MCP_IDENTITY_HEADERS.avatarId)??"",email:r(MCP_IDENTITY_HEADERS.email)??"",rolesHeader:r(MCP_IDENTITY_HEADERS.roles)??"[]",requestId:r(MCP_IDENTITY_HEADERS.requestId),issuedAt:r(MCP_IDENTITY_HEADERS.issuedAt),signature:r(MCP_IDENTITY_HEADERS.signature)},{version:s,serverId:i,keyVersion:d,userId:I,tenantId:u,requestId:y,issuedAt:n,signature:f}=t;if(!s||!i||!d||!I||!u||!y||!n||!f)return{ok:!1,reason:"missing_headers"};if(s!==MCP_IDENTITY_VERSION)return{ok:!1,reason:"unsupported_version"};if(e.expectedServerId&&i!==e.expectedServerId)return{ok:!1,reason:"unknown_server"};const _=e.keys[d];if(!_)return{ok:!1,reason:"unknown_key_version"};const g=Number(n);if(!/^\d+$/.test(n)||Math.abs(e.nowMs-g)>MCP_IDENTITY_MAX_SKEW_MS)return{ok:!1,reason:"stale"};const c={serverId:i,keyVersion:d,userId:I,tenantId:u,avatarId:t.avatarId,email:t.email,rolesHeader:t.rolesHeader,requestId:y,issuedAt:n};let l;try{l=Buffer.from(signMcpIdentity(c,{method:e.method,pathAndQuery:e.pathAndQuery,bodySha256:sha256Hex(e.body??"")},_))}catch{return{ok:!1,reason:"bad_signature"}}const E=Buffer.from(f);if(l.length!==E.length||!crypto.timingSafeEqual(l,E))return{ok:!1,reason:"bad_signature"};let o;try{o=JSON.parse(t.rolesHeader)}catch{return{ok:!1,reason:"malformed_roles"}}return!Array.isArray(o)||!o.every(v=>typeof v=="string")?{ok:!1,reason:"malformed_roles"}:{ok:!0,identity:{serverId:i,keyVersion:d,userId:I,tenantId:u,avatarId:t.avatarId,email:t.email,roles:o,requestId:y,issuedAt:g}}}a(verifyMcpIdentity,"verifyMcpIdentity"),exports.MCP_IDENTITY_HEADERS=MCP_IDENTITY_HEADERS,exports.MCP_IDENTITY_HEADER_PREFIX=MCP_IDENTITY_HEADER_PREFIX,exports.MCP_IDENTITY_MAX_SKEW_MS=MCP_IDENTITY_MAX_SKEW_MS,exports.MCP_IDENTITY_MESSAGE_PREFIX=MCP_IDENTITY_MESSAGE_PREFIX,exports.MCP_IDENTITY_VERSION=MCP_IDENTITY_VERSION,exports.buildMcpIdentityHeaders=buildMcpIdentityHeaders,exports.sha256Hex=sha256Hex,exports.signMcpIdentity=signMcpIdentity,exports.verifyMcpIdentity=verifyMcpIdentity;
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Proof of who an MCP tool call acts for, as a downstream HTTP service sees it.
|
|
3
|
+
*
|
|
4
|
+
* tego-mcp relays a tool call to a service outside the platform — an intranet
|
|
5
|
+
* system, a team's own API. That service never receives the container's
|
|
6
|
+
* gateway token: it would be a standing credential for every user of the
|
|
7
|
+
* avatar. It receives the identity tego-server verified instead, signed per
|
|
8
|
+
* request with a key that belongs to that one MCP server.
|
|
9
|
+
*
|
|
10
|
+
* The key is random and stored by tego-mcp rather than derived from a platform
|
|
11
|
+
* secret. Avatar containers hold the platform JWT secret to verify user tokens
|
|
12
|
+
* locally, so anything derived from it is computable inside a container — and
|
|
13
|
+
* the point of this signature is that a container cannot produce it.
|
|
14
|
+
*
|
|
15
|
+
* The signature covers the request itself (method, path and query, body hash),
|
|
16
|
+
* not only the identity, so a captured header set cannot be replayed against
|
|
17
|
+
* another endpoint or with another body.
|
|
18
|
+
*
|
|
19
|
+
* Both ends live here so there is one definition of the signed bytes; the
|
|
20
|
+
* Python SDK is held to the same vector file.
|
|
21
|
+
*/
|
|
22
|
+
declare const MCP_IDENTITY_VERSION = "1";
|
|
23
|
+
declare const MCP_IDENTITY_MESSAGE_PREFIX = "tego-mcp-identity-v1";
|
|
24
|
+
/** Same window as the plugin gateway: loose enough for NTP-synced hosts. */
|
|
25
|
+
declare const MCP_IDENTITY_MAX_SKEW_MS: number;
|
|
26
|
+
declare const MCP_IDENTITY_HEADERS: {
|
|
27
|
+
readonly version: "x-tego-identity-version";
|
|
28
|
+
readonly serverId: "x-tego-identity-server-id";
|
|
29
|
+
readonly keyVersion: "x-tego-identity-key-version";
|
|
30
|
+
readonly userId: "x-tego-identity-user-id";
|
|
31
|
+
readonly tenantId: "x-tego-identity-tenant-id";
|
|
32
|
+
readonly avatarId: "x-tego-identity-avatar-id";
|
|
33
|
+
readonly email: "x-tego-identity-email";
|
|
34
|
+
readonly roles: "x-tego-identity-roles";
|
|
35
|
+
readonly requestId: "x-tego-identity-request-id";
|
|
36
|
+
readonly issuedAt: "x-tego-identity-issued-at";
|
|
37
|
+
readonly signature: "x-tego-identity-signature";
|
|
38
|
+
};
|
|
39
|
+
/** Every identity header, for callers that must strip or forbid them. */
|
|
40
|
+
declare const MCP_IDENTITY_HEADER_PREFIX = "x-tego-identity-";
|
|
41
|
+
interface McpIdentityContext {
|
|
42
|
+
serverId: string;
|
|
43
|
+
keyVersion: string;
|
|
44
|
+
userId: string;
|
|
45
|
+
tenantId: string;
|
|
46
|
+
/** Empty string when the caller is a person rather than an avatar. */
|
|
47
|
+
avatarId: string;
|
|
48
|
+
/** Empty string when the user has none. */
|
|
49
|
+
email: string;
|
|
50
|
+
/** The `roles` header verbatim — a JSON array — never re-serialized. */
|
|
51
|
+
rolesHeader: string;
|
|
52
|
+
requestId: string;
|
|
53
|
+
/** Unix milliseconds, as it appears in the header. */
|
|
54
|
+
issuedAt: string;
|
|
55
|
+
}
|
|
56
|
+
interface McpIdentityRequest {
|
|
57
|
+
method: string;
|
|
58
|
+
/** Path and query exactly as sent, e.g. `/orders?status=open`. */
|
|
59
|
+
pathAndQuery: string;
|
|
60
|
+
/** Lowercase hex SHA-256 of the body bytes; of the empty string when none. */
|
|
61
|
+
bodySha256: string;
|
|
62
|
+
}
|
|
63
|
+
declare function sha256Hex(body?: string | Uint8Array): string;
|
|
64
|
+
declare function signMcpIdentity(context: McpIdentityContext, request: McpIdentityRequest, key: string): string;
|
|
65
|
+
/** The full header set for one signed request. */
|
|
66
|
+
declare function buildMcpIdentityHeaders(context: McpIdentityContext, request: McpIdentityRequest, key: string): Record<string, string>;
|
|
67
|
+
interface VerifiedMcpIdentity {
|
|
68
|
+
serverId: string;
|
|
69
|
+
keyVersion: string;
|
|
70
|
+
userId: string;
|
|
71
|
+
tenantId: string;
|
|
72
|
+
avatarId: string;
|
|
73
|
+
email: string;
|
|
74
|
+
roles: string[];
|
|
75
|
+
requestId: string;
|
|
76
|
+
issuedAt: number;
|
|
77
|
+
}
|
|
78
|
+
type McpIdentityVerification = {
|
|
79
|
+
ok: true;
|
|
80
|
+
identity: VerifiedMcpIdentity;
|
|
81
|
+
} | {
|
|
82
|
+
ok: false;
|
|
83
|
+
reason: 'missing_headers' | 'unsupported_version' | 'unknown_server' | 'unknown_key_version' | 'stale' | 'bad_signature' | 'malformed_roles';
|
|
84
|
+
};
|
|
85
|
+
type HeaderReader = Record<string, string | string[] | undefined> | {
|
|
86
|
+
get(name: string): string | null;
|
|
87
|
+
};
|
|
88
|
+
/**
|
|
89
|
+
* Whether a request carries a recent identity signed by one of `keys`.
|
|
90
|
+
*
|
|
91
|
+
* `keys` maps a key version to its secret, so a service can accept the
|
|
92
|
+
* previous key for the grace period after a rotation. `expectedServerId`
|
|
93
|
+
* pins the MCP server the service was configured for; leave it out only when
|
|
94
|
+
* one key set is shared deliberately.
|
|
95
|
+
*/
|
|
96
|
+
declare function verifyMcpIdentity(input: {
|
|
97
|
+
headers: HeaderReader;
|
|
98
|
+
method: string;
|
|
99
|
+
pathAndQuery: string;
|
|
100
|
+
body?: string | Uint8Array;
|
|
101
|
+
keys: Record<string, string>;
|
|
102
|
+
nowMs: number;
|
|
103
|
+
expectedServerId?: string;
|
|
104
|
+
}): McpIdentityVerification;
|
|
105
|
+
|
|
106
|
+
export { MCP_IDENTITY_HEADERS, MCP_IDENTITY_HEADER_PREFIX, MCP_IDENTITY_MAX_SKEW_MS, MCP_IDENTITY_MESSAGE_PREFIX, MCP_IDENTITY_VERSION, type McpIdentityContext, type McpIdentityRequest, type McpIdentityVerification, type VerifiedMcpIdentity, buildMcpIdentityHeaders, sha256Hex, signMcpIdentity, verifyMcpIdentity };
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Proof of who an MCP tool call acts for, as a downstream HTTP service sees it.
|
|
3
|
+
*
|
|
4
|
+
* tego-mcp relays a tool call to a service outside the platform — an intranet
|
|
5
|
+
* system, a team's own API. That service never receives the container's
|
|
6
|
+
* gateway token: it would be a standing credential for every user of the
|
|
7
|
+
* avatar. It receives the identity tego-server verified instead, signed per
|
|
8
|
+
* request with a key that belongs to that one MCP server.
|
|
9
|
+
*
|
|
10
|
+
* The key is random and stored by tego-mcp rather than derived from a platform
|
|
11
|
+
* secret. Avatar containers hold the platform JWT secret to verify user tokens
|
|
12
|
+
* locally, so anything derived from it is computable inside a container — and
|
|
13
|
+
* the point of this signature is that a container cannot produce it.
|
|
14
|
+
*
|
|
15
|
+
* The signature covers the request itself (method, path and query, body hash),
|
|
16
|
+
* not only the identity, so a captured header set cannot be replayed against
|
|
17
|
+
* another endpoint or with another body.
|
|
18
|
+
*
|
|
19
|
+
* Both ends live here so there is one definition of the signed bytes; the
|
|
20
|
+
* Python SDK is held to the same vector file.
|
|
21
|
+
*/
|
|
22
|
+
declare const MCP_IDENTITY_VERSION = "1";
|
|
23
|
+
declare const MCP_IDENTITY_MESSAGE_PREFIX = "tego-mcp-identity-v1";
|
|
24
|
+
/** Same window as the plugin gateway: loose enough for NTP-synced hosts. */
|
|
25
|
+
declare const MCP_IDENTITY_MAX_SKEW_MS: number;
|
|
26
|
+
declare const MCP_IDENTITY_HEADERS: {
|
|
27
|
+
readonly version: "x-tego-identity-version";
|
|
28
|
+
readonly serverId: "x-tego-identity-server-id";
|
|
29
|
+
readonly keyVersion: "x-tego-identity-key-version";
|
|
30
|
+
readonly userId: "x-tego-identity-user-id";
|
|
31
|
+
readonly tenantId: "x-tego-identity-tenant-id";
|
|
32
|
+
readonly avatarId: "x-tego-identity-avatar-id";
|
|
33
|
+
readonly email: "x-tego-identity-email";
|
|
34
|
+
readonly roles: "x-tego-identity-roles";
|
|
35
|
+
readonly requestId: "x-tego-identity-request-id";
|
|
36
|
+
readonly issuedAt: "x-tego-identity-issued-at";
|
|
37
|
+
readonly signature: "x-tego-identity-signature";
|
|
38
|
+
};
|
|
39
|
+
/** Every identity header, for callers that must strip or forbid them. */
|
|
40
|
+
declare const MCP_IDENTITY_HEADER_PREFIX = "x-tego-identity-";
|
|
41
|
+
interface McpIdentityContext {
|
|
42
|
+
serverId: string;
|
|
43
|
+
keyVersion: string;
|
|
44
|
+
userId: string;
|
|
45
|
+
tenantId: string;
|
|
46
|
+
/** Empty string when the caller is a person rather than an avatar. */
|
|
47
|
+
avatarId: string;
|
|
48
|
+
/** Empty string when the user has none. */
|
|
49
|
+
email: string;
|
|
50
|
+
/** The `roles` header verbatim — a JSON array — never re-serialized. */
|
|
51
|
+
rolesHeader: string;
|
|
52
|
+
requestId: string;
|
|
53
|
+
/** Unix milliseconds, as it appears in the header. */
|
|
54
|
+
issuedAt: string;
|
|
55
|
+
}
|
|
56
|
+
interface McpIdentityRequest {
|
|
57
|
+
method: string;
|
|
58
|
+
/** Path and query exactly as sent, e.g. `/orders?status=open`. */
|
|
59
|
+
pathAndQuery: string;
|
|
60
|
+
/** Lowercase hex SHA-256 of the body bytes; of the empty string when none. */
|
|
61
|
+
bodySha256: string;
|
|
62
|
+
}
|
|
63
|
+
declare function sha256Hex(body?: string | Uint8Array): string;
|
|
64
|
+
declare function signMcpIdentity(context: McpIdentityContext, request: McpIdentityRequest, key: string): string;
|
|
65
|
+
/** The full header set for one signed request. */
|
|
66
|
+
declare function buildMcpIdentityHeaders(context: McpIdentityContext, request: McpIdentityRequest, key: string): Record<string, string>;
|
|
67
|
+
interface VerifiedMcpIdentity {
|
|
68
|
+
serverId: string;
|
|
69
|
+
keyVersion: string;
|
|
70
|
+
userId: string;
|
|
71
|
+
tenantId: string;
|
|
72
|
+
avatarId: string;
|
|
73
|
+
email: string;
|
|
74
|
+
roles: string[];
|
|
75
|
+
requestId: string;
|
|
76
|
+
issuedAt: number;
|
|
77
|
+
}
|
|
78
|
+
type McpIdentityVerification = {
|
|
79
|
+
ok: true;
|
|
80
|
+
identity: VerifiedMcpIdentity;
|
|
81
|
+
} | {
|
|
82
|
+
ok: false;
|
|
83
|
+
reason: 'missing_headers' | 'unsupported_version' | 'unknown_server' | 'unknown_key_version' | 'stale' | 'bad_signature' | 'malformed_roles';
|
|
84
|
+
};
|
|
85
|
+
type HeaderReader = Record<string, string | string[] | undefined> | {
|
|
86
|
+
get(name: string): string | null;
|
|
87
|
+
};
|
|
88
|
+
/**
|
|
89
|
+
* Whether a request carries a recent identity signed by one of `keys`.
|
|
90
|
+
*
|
|
91
|
+
* `keys` maps a key version to its secret, so a service can accept the
|
|
92
|
+
* previous key for the grace period after a rotation. `expectedServerId`
|
|
93
|
+
* pins the MCP server the service was configured for; leave it out only when
|
|
94
|
+
* one key set is shared deliberately.
|
|
95
|
+
*/
|
|
96
|
+
declare function verifyMcpIdentity(input: {
|
|
97
|
+
headers: HeaderReader;
|
|
98
|
+
method: string;
|
|
99
|
+
pathAndQuery: string;
|
|
100
|
+
body?: string | Uint8Array;
|
|
101
|
+
keys: Record<string, string>;
|
|
102
|
+
nowMs: number;
|
|
103
|
+
expectedServerId?: string;
|
|
104
|
+
}): McpIdentityVerification;
|
|
105
|
+
|
|
106
|
+
export { MCP_IDENTITY_HEADERS, MCP_IDENTITY_HEADER_PREFIX, MCP_IDENTITY_MAX_SKEW_MS, MCP_IDENTITY_MESSAGE_PREFIX, MCP_IDENTITY_VERSION, type McpIdentityContext, type McpIdentityRequest, type McpIdentityVerification, type VerifiedMcpIdentity, buildMcpIdentityHeaders, sha256Hex, signMcpIdentity, verifyMcpIdentity };
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
var H=Object.defineProperty;var i=(e,r)=>H(e,"name",{value:r,configurable:!0});import{createHash as S,createHmac as b,timingSafeEqual as T}from"crypto";var g="1",A="tego-mcp-identity-v1",E=300*1e3,t={version:"x-tego-identity-version",serverId:"x-tego-identity-server-id",keyVersion:"x-tego-identity-key-version",userId:"x-tego-identity-user-id",tenantId:"x-tego-identity-tenant-id",avatarId:"x-tego-identity-avatar-id",email:"x-tego-identity-email",roles:"x-tego-identity-roles",requestId:"x-tego-identity-request-id",issuedAt:"x-tego-identity-issued-at",signature:"x-tego-identity-signature"},C="x-tego-identity-";function M(e=""){return S("sha256").update(e).digest("hex")}i(M,"sha256Hex");function N(e,r){const s=[A,e.serverId,e.keyVersion,r.method.toUpperCase(),r.pathAndQuery,r.bodySha256,e.userId,e.tenantId,e.avatarId,e.email,e.rolesHeader,e.requestId,e.issuedAt];if(s.some(a=>/[\r\n]/.test(a)))throw new Error("MCP identity fields must not contain line breaks");return s.join(`
|
|
2
|
+
`)}i(N,"canonicalMessage");function m(e,r,s){return b("sha256",s).update(N(e,r)).digest("hex")}i(m,"signMcpIdentity");function P(e,r,s){return{[t.version]:g,[t.serverId]:e.serverId,[t.keyVersion]:e.keyVersion,[t.userId]:e.userId,[t.tenantId]:e.tenantId,[t.avatarId]:e.avatarId,[t.email]:e.email,[t.roles]:e.rolesHeader,[t.requestId]:e.requestId,[t.issuedAt]:e.issuedAt,[t.signature]:m(e,r,s)}}i(P,"buildMcpIdentityHeaders");function V(e,r){if(typeof e.get=="function")return e.get(r)??void 0;const s=e,a=s[r]??Object.entries(s).find(([d])=>d.toLowerCase()===r)?.[1];return Array.isArray(a)?a[0]:a}i(V,"readHeader");function q(e){const r=i(f=>V(e.headers,f),"read"),s={version:r(t.version),serverId:r(t.serverId),keyVersion:r(t.keyVersion),userId:r(t.userId),tenantId:r(t.tenantId),avatarId:r(t.avatarId)??"",email:r(t.email)??"",rolesHeader:r(t.roles)??"[]",requestId:r(t.requestId),issuedAt:r(t.issuedAt),signature:r(t.signature)},{version:a,serverId:d,keyVersion:n,userId:I,tenantId:l,requestId:y,issuedAt:o,signature:k}=s;if(!a||!d||!n||!I||!l||!y||!o||!k)return{ok:!1,reason:"missing_headers"};if(a!==g)return{ok:!1,reason:"unsupported_version"};if(e.expectedServerId&&d!==e.expectedServerId)return{ok:!1,reason:"unknown_server"};const _=e.keys[n];if(!_)return{ok:!1,reason:"unknown_key_version"};const c=Number(o);if(!/^\d+$/.test(o)||Math.abs(e.nowMs-c)>E)return{ok:!1,reason:"stale"};const p={serverId:d,keyVersion:n,userId:I,tenantId:l,avatarId:s.avatarId,email:s.email,rolesHeader:s.rolesHeader,requestId:y,issuedAt:o};let v;try{v=Buffer.from(m(p,{method:e.method,pathAndQuery:e.pathAndQuery,bodySha256:M(e.body??"")},_))}catch{return{ok:!1,reason:"bad_signature"}}const h=Buffer.from(k);if(v.length!==h.length||!T(v,h))return{ok:!1,reason:"bad_signature"};let u;try{u=JSON.parse(s.rolesHeader)}catch{return{ok:!1,reason:"malformed_roles"}}return!Array.isArray(u)||!u.every(f=>typeof f=="string")?{ok:!1,reason:"malformed_roles"}:{ok:!0,identity:{serverId:d,keyVersion:n,userId:I,tenantId:l,avatarId:s.avatarId,email:s.email,roles:u,requestId:y,issuedAt:c}}}i(q,"verifyMcpIdentity");export{t as MCP_IDENTITY_HEADERS,C as MCP_IDENTITY_HEADER_PREFIX,E as MCP_IDENTITY_MAX_SKEW_MS,A as MCP_IDENTITY_MESSAGE_PREFIX,g as MCP_IDENTITY_VERSION,P as buildMcpIdentityHeaders,M as sha256Hex,m as signMcpIdentity,q as verifyMcpIdentity};
|
package/dist/pack.cjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";var u=Object.defineProperty;var e=(r,n)=>u(r,"name",{value:n,configurable:!0});var chunkTHMWRUAT_cjs=require("./chunk-THMWRUAT.cjs");require("./chunk-W7C357A6.cjs"),require("./chunk-3WA3M347.cjs"),require("./chunk-ROFUQLOZ.cjs"),require("./chunk-C2OCOPZQ.cjs"),require("./chunk-AJY7ZHXK.cjs"),require("./chunk-OP64Y4IN.cjs"),Object.defineProperty(exports,"buildAgentTemplate",{enumerable:!0,get:e(function(){return chunkTHMWRUAT_cjs.buildAgentTemplate},"get")}),Object.defineProperty(exports,"buildPluginBackend",{enumerable:!0,get:e(function(){return chunkTHMWRUAT_cjs.buildPluginBackend},"get")}),Object.defineProperty(exports,"buildPluginTemplates",{enumerable:!0,get:e(function(){return chunkTHMWRUAT_cjs.buildPluginTemplates},"get")}),Object.defineProperty(exports,"lockPlugin",{enumerable:!0,get:e(function(){return chunkTHMWRUAT_cjs.lockPlugin},"get")}),Object.defineProperty(exports,"packPlugin",{enumerable:!0,get:e(function(){return chunkTHMWRUAT_cjs.packPlugin},"get")}),Object.defineProperty(exports,"watchPluginFrontend",{enumerable:!0,get:e(function(){return chunkTHMWRUAT_cjs.watchPluginFrontend},"get")});
|
package/dist/pack.d.cts
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import { T as TegoPluginManifest, R as ResolvedBackendPart } from './manifest-types-DQARCQJt.cjs';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Staging a `runtime: "python"` backend: source, locked wheels, and a lock
|
|
5
|
+
* whose hashes are exactly the wheels shipped.
|
|
6
|
+
*
|
|
7
|
+
* Two locks, deliberately different:
|
|
8
|
+
*
|
|
9
|
+
* - the plugin's `backend/requirements.lock` is the provenance record —
|
|
10
|
+
* compiled by `tego-plugin-pack lock` with hashes of what PyPI serves, and
|
|
11
|
+
* committed;
|
|
12
|
+
* - the packaged lock is what the runner installs with `--require-hashes` —
|
|
13
|
+
* one line per package with the hashes of the wheels in the archive.
|
|
14
|
+
*
|
|
15
|
+
* They differ only where a locked package has no wheel on PyPI (pure-python
|
|
16
|
+
* sdists such as `antlr4-python3-runtime`). Those are downloaded against the
|
|
17
|
+
* provenance hash, built here into a wheel, and the built wheel's hash is what
|
|
18
|
+
* the package records. A sdist with native code builds a wheel for this
|
|
19
|
+
* machine, not for linux, and `checkPythonVendoring` then refuses it by name.
|
|
20
|
+
*
|
|
21
|
+
* Needs `uv` on PATH. pip does the downloading (through `uvx`), because it is
|
|
22
|
+
* the tool that can fetch for a foreign platform while verifying hashes.
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
interface PythonBackendOptions {
|
|
26
|
+
/**
|
|
27
|
+
* Paths relative to the backend dir to ship besides the entry. Defaults to
|
|
28
|
+
* `src`, `resources`, `migrations`. An allowlist so a stray `.env` or
|
|
29
|
+
* `.venv` never ends up in a release.
|
|
30
|
+
*/
|
|
31
|
+
include?: string[];
|
|
32
|
+
/**
|
|
33
|
+
* Directory of the `tego-plugin-sdk` python project. Defaults to the
|
|
34
|
+
* nearest `packages/plugin-sdk-python` above the plugin root.
|
|
35
|
+
*/
|
|
36
|
+
sdkProject?: string;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** Returns the `template.json` text (with trailing newline) for `dir`. */
|
|
40
|
+
declare function buildAgentTemplate(dir: string): Promise<string>;
|
|
41
|
+
|
|
42
|
+
/** Everything a plugin may need to say that the conventions cannot infer. */
|
|
43
|
+
interface PackPluginOptions {
|
|
44
|
+
/** Package root: the directory holding `tego.plugin.json`. */
|
|
45
|
+
root: string;
|
|
46
|
+
/** Where to write the archive. Defaults to `<root>/build`. */
|
|
47
|
+
outDir?: string;
|
|
48
|
+
/** Archive filename. Defaults to `<id>-<version>.zip`. */
|
|
49
|
+
fileName?: string;
|
|
50
|
+
frontend?: {
|
|
51
|
+
/** Vite config, relative to root. Defaults to `<dir>/vite.config.ts`. */
|
|
52
|
+
viteConfig?: string;
|
|
53
|
+
/**
|
|
54
|
+
* Where the vite build writes. Defaults to `<dir>/dist`, matching the
|
|
55
|
+
* `outDir` the SDK's vite preset defaults to.
|
|
56
|
+
*/
|
|
57
|
+
buildDir?: string;
|
|
58
|
+
};
|
|
59
|
+
/**
|
|
60
|
+
* The anonymous pages. A standalone vite app, not a host module: it is
|
|
61
|
+
* served as a document of its own, so its config should set `base: './'`
|
|
62
|
+
* and emit `index.html`.
|
|
63
|
+
*/
|
|
64
|
+
publicFrontend?: {
|
|
65
|
+
/** Vite config, relative to root. Defaults to `<dir>/vite.config.ts`. */
|
|
66
|
+
viteConfig?: string;
|
|
67
|
+
/** Where the vite build writes. Defaults to `<dir>/dist`. */
|
|
68
|
+
buildDir?: string;
|
|
69
|
+
};
|
|
70
|
+
backend?: {
|
|
71
|
+
/** Entry source, relative to root. Defaults to `<dir>/src/index.ts`. */
|
|
72
|
+
entry?: string;
|
|
73
|
+
/** Extra modules to leave unbundled, on top of the built-in list. */
|
|
74
|
+
external?: string[];
|
|
75
|
+
/** Only for `runtime: "python"`. */
|
|
76
|
+
python?: PythonBackendOptions;
|
|
77
|
+
};
|
|
78
|
+
claw?: {
|
|
79
|
+
/** Entry source, relative to root. Defaults to `<dir>/src/index.ts`. */
|
|
80
|
+
entry?: string;
|
|
81
|
+
/** Skills directory, relative to root. Defaults to `<dir>/skills`. */
|
|
82
|
+
skillsDir?: string;
|
|
83
|
+
/** Extra modules to leave unbundled, on top of the built-in list. */
|
|
84
|
+
external?: string[];
|
|
85
|
+
};
|
|
86
|
+
/** Where to report progress. Defaults to `console.log`. Pass `null` to mute. */
|
|
87
|
+
log?: ((message: string) => void) | null;
|
|
88
|
+
}
|
|
89
|
+
interface PackedPlugin {
|
|
90
|
+
/** Absolute path of the archive. */
|
|
91
|
+
file: string;
|
|
92
|
+
bytes: number;
|
|
93
|
+
/** Hex sha256 of the archive, the same digest the upload endpoint records. */
|
|
94
|
+
sha256: string;
|
|
95
|
+
manifest: TegoPluginManifest;
|
|
96
|
+
}
|
|
97
|
+
declare function packPlugin(options: PackPluginOptions): Promise<PackedPlugin>;
|
|
98
|
+
/**
|
|
99
|
+
* Rebuild every declared template authored in directory form (a
|
|
100
|
+
* `template.config.json` beside its entry) and write its `template.json`.
|
|
101
|
+
*
|
|
102
|
+
* The built file is committed so a reviewer sees what ships; packing rebuilds
|
|
103
|
+
* it first, so a package never carries a stale one. Returns the entries that
|
|
104
|
+
* changed.
|
|
105
|
+
*/
|
|
106
|
+
declare function buildPluginTemplates(options: {
|
|
107
|
+
root: string;
|
|
108
|
+
log?: PackPluginOptions['log'];
|
|
109
|
+
}): Promise<string[]>;
|
|
110
|
+
/**
|
|
111
|
+
* Re-compile a python backend's `requirements.lock` from `requirements.in`.
|
|
112
|
+
* Commit the result: it is the provenance every pack verifies against.
|
|
113
|
+
*/
|
|
114
|
+
declare function lockPlugin(options: {
|
|
115
|
+
root: string;
|
|
116
|
+
python?: PythonBackendOptions;
|
|
117
|
+
}): Promise<string>;
|
|
118
|
+
interface WatchPluginOptions {
|
|
119
|
+
/** Package root: the directory holding `tego.plugin.json`. */
|
|
120
|
+
root: string;
|
|
121
|
+
/** Port for the local bundle server. Defaults to 5180. */
|
|
122
|
+
port?: number;
|
|
123
|
+
frontend?: PackPluginOptions['frontend'];
|
|
124
|
+
log?: PackPluginOptions['log'];
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Rebuild the frontend part on change and serve it over HTTP.
|
|
128
|
+
*
|
|
129
|
+
* The loop this replaces is pack → upload → install → refresh, which is a
|
|
130
|
+
* minute per one-line change. With this running and
|
|
131
|
+
* `VITE_TEGO_LOCAL_PLUGINS=<id>=http://localhost:5180/index.js` set on the
|
|
132
|
+
* shell, saving a file rebuilds the bundle and reloads the plugin page.
|
|
133
|
+
*
|
|
134
|
+
* **No module-level HMR.** State inside the plugin page is lost on every
|
|
135
|
+
* rebuild. Hot replacement across the SystemJS boundary would mean unmounting
|
|
136
|
+
* the plugin's own React root and re-registering shared modules, which is a
|
|
137
|
+
* lot of machinery for something that would silently desync; a reload takes
|
|
138
|
+
* about a second and is always right.
|
|
139
|
+
*
|
|
140
|
+
* Frontend only. The backend runs on the host through
|
|
141
|
+
* `run-plugin-backend-locally.ts`, and the claw part runs inside a container
|
|
142
|
+
* that has to be given a new bundle either way.
|
|
143
|
+
*
|
|
144
|
+
* Never resolves — the caller is a foreground command the author interrupts.
|
|
145
|
+
*/
|
|
146
|
+
declare function watchPluginFrontend(options: WatchPluginOptions): Promise<never>;
|
|
147
|
+
interface BuildPluginBackendOptions {
|
|
148
|
+
/** Package root: the directory holding `tego.plugin.json`. */
|
|
149
|
+
root: string;
|
|
150
|
+
/**
|
|
151
|
+
* Where to write, using the part's own layout — the entry lands at
|
|
152
|
+
* `<outDir>/<part.entryPath>`, migrations and the `type: module` marker
|
|
153
|
+
* beside it. In a pack this is the staging dir; the local dev runner points
|
|
154
|
+
* it straight at its scratch dir and skips the zip entirely.
|
|
155
|
+
*/
|
|
156
|
+
outDir: string;
|
|
157
|
+
/** Source entry, relative to root. Defaults to `<dir>/src/index.ts`. */
|
|
158
|
+
entry?: string;
|
|
159
|
+
/** Extra modules to leave unbundled, on top of the built-in list. */
|
|
160
|
+
external?: string[];
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Build one plugin's backend the way the packer does — one definition of the
|
|
164
|
+
* externals, the target and the emitted `package.json`, so the local dev
|
|
165
|
+
* rebuild loop cannot drift from what a release actually ships.
|
|
166
|
+
*/
|
|
167
|
+
declare function buildPluginBackend(part: ResolvedBackendPart, options: BuildPluginBackendOptions): Promise<void>;
|
|
168
|
+
|
|
169
|
+
export { type BuildPluginBackendOptions, type PackPluginOptions, type PackedPlugin, type WatchPluginOptions, buildAgentTemplate, buildPluginBackend, buildPluginTemplates, lockPlugin, packPlugin, watchPluginFrontend };
|
package/dist/pack.d.ts
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import { T as TegoPluginManifest, R as ResolvedBackendPart } from './manifest-types-DQARCQJt.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Staging a `runtime: "python"` backend: source, locked wheels, and a lock
|
|
5
|
+
* whose hashes are exactly the wheels shipped.
|
|
6
|
+
*
|
|
7
|
+
* Two locks, deliberately different:
|
|
8
|
+
*
|
|
9
|
+
* - the plugin's `backend/requirements.lock` is the provenance record —
|
|
10
|
+
* compiled by `tego-plugin-pack lock` with hashes of what PyPI serves, and
|
|
11
|
+
* committed;
|
|
12
|
+
* - the packaged lock is what the runner installs with `--require-hashes` —
|
|
13
|
+
* one line per package with the hashes of the wheels in the archive.
|
|
14
|
+
*
|
|
15
|
+
* They differ only where a locked package has no wheel on PyPI (pure-python
|
|
16
|
+
* sdists such as `antlr4-python3-runtime`). Those are downloaded against the
|
|
17
|
+
* provenance hash, built here into a wheel, and the built wheel's hash is what
|
|
18
|
+
* the package records. A sdist with native code builds a wheel for this
|
|
19
|
+
* machine, not for linux, and `checkPythonVendoring` then refuses it by name.
|
|
20
|
+
*
|
|
21
|
+
* Needs `uv` on PATH. pip does the downloading (through `uvx`), because it is
|
|
22
|
+
* the tool that can fetch for a foreign platform while verifying hashes.
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
interface PythonBackendOptions {
|
|
26
|
+
/**
|
|
27
|
+
* Paths relative to the backend dir to ship besides the entry. Defaults to
|
|
28
|
+
* `src`, `resources`, `migrations`. An allowlist so a stray `.env` or
|
|
29
|
+
* `.venv` never ends up in a release.
|
|
30
|
+
*/
|
|
31
|
+
include?: string[];
|
|
32
|
+
/**
|
|
33
|
+
* Directory of the `tego-plugin-sdk` python project. Defaults to the
|
|
34
|
+
* nearest `packages/plugin-sdk-python` above the plugin root.
|
|
35
|
+
*/
|
|
36
|
+
sdkProject?: string;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** Returns the `template.json` text (with trailing newline) for `dir`. */
|
|
40
|
+
declare function buildAgentTemplate(dir: string): Promise<string>;
|
|
41
|
+
|
|
42
|
+
/** Everything a plugin may need to say that the conventions cannot infer. */
|
|
43
|
+
interface PackPluginOptions {
|
|
44
|
+
/** Package root: the directory holding `tego.plugin.json`. */
|
|
45
|
+
root: string;
|
|
46
|
+
/** Where to write the archive. Defaults to `<root>/build`. */
|
|
47
|
+
outDir?: string;
|
|
48
|
+
/** Archive filename. Defaults to `<id>-<version>.zip`. */
|
|
49
|
+
fileName?: string;
|
|
50
|
+
frontend?: {
|
|
51
|
+
/** Vite config, relative to root. Defaults to `<dir>/vite.config.ts`. */
|
|
52
|
+
viteConfig?: string;
|
|
53
|
+
/**
|
|
54
|
+
* Where the vite build writes. Defaults to `<dir>/dist`, matching the
|
|
55
|
+
* `outDir` the SDK's vite preset defaults to.
|
|
56
|
+
*/
|
|
57
|
+
buildDir?: string;
|
|
58
|
+
};
|
|
59
|
+
/**
|
|
60
|
+
* The anonymous pages. A standalone vite app, not a host module: it is
|
|
61
|
+
* served as a document of its own, so its config should set `base: './'`
|
|
62
|
+
* and emit `index.html`.
|
|
63
|
+
*/
|
|
64
|
+
publicFrontend?: {
|
|
65
|
+
/** Vite config, relative to root. Defaults to `<dir>/vite.config.ts`. */
|
|
66
|
+
viteConfig?: string;
|
|
67
|
+
/** Where the vite build writes. Defaults to `<dir>/dist`. */
|
|
68
|
+
buildDir?: string;
|
|
69
|
+
};
|
|
70
|
+
backend?: {
|
|
71
|
+
/** Entry source, relative to root. Defaults to `<dir>/src/index.ts`. */
|
|
72
|
+
entry?: string;
|
|
73
|
+
/** Extra modules to leave unbundled, on top of the built-in list. */
|
|
74
|
+
external?: string[];
|
|
75
|
+
/** Only for `runtime: "python"`. */
|
|
76
|
+
python?: PythonBackendOptions;
|
|
77
|
+
};
|
|
78
|
+
claw?: {
|
|
79
|
+
/** Entry source, relative to root. Defaults to `<dir>/src/index.ts`. */
|
|
80
|
+
entry?: string;
|
|
81
|
+
/** Skills directory, relative to root. Defaults to `<dir>/skills`. */
|
|
82
|
+
skillsDir?: string;
|
|
83
|
+
/** Extra modules to leave unbundled, on top of the built-in list. */
|
|
84
|
+
external?: string[];
|
|
85
|
+
};
|
|
86
|
+
/** Where to report progress. Defaults to `console.log`. Pass `null` to mute. */
|
|
87
|
+
log?: ((message: string) => void) | null;
|
|
88
|
+
}
|
|
89
|
+
interface PackedPlugin {
|
|
90
|
+
/** Absolute path of the archive. */
|
|
91
|
+
file: string;
|
|
92
|
+
bytes: number;
|
|
93
|
+
/** Hex sha256 of the archive, the same digest the upload endpoint records. */
|
|
94
|
+
sha256: string;
|
|
95
|
+
manifest: TegoPluginManifest;
|
|
96
|
+
}
|
|
97
|
+
declare function packPlugin(options: PackPluginOptions): Promise<PackedPlugin>;
|
|
98
|
+
/**
|
|
99
|
+
* Rebuild every declared template authored in directory form (a
|
|
100
|
+
* `template.config.json` beside its entry) and write its `template.json`.
|
|
101
|
+
*
|
|
102
|
+
* The built file is committed so a reviewer sees what ships; packing rebuilds
|
|
103
|
+
* it first, so a package never carries a stale one. Returns the entries that
|
|
104
|
+
* changed.
|
|
105
|
+
*/
|
|
106
|
+
declare function buildPluginTemplates(options: {
|
|
107
|
+
root: string;
|
|
108
|
+
log?: PackPluginOptions['log'];
|
|
109
|
+
}): Promise<string[]>;
|
|
110
|
+
/**
|
|
111
|
+
* Re-compile a python backend's `requirements.lock` from `requirements.in`.
|
|
112
|
+
* Commit the result: it is the provenance every pack verifies against.
|
|
113
|
+
*/
|
|
114
|
+
declare function lockPlugin(options: {
|
|
115
|
+
root: string;
|
|
116
|
+
python?: PythonBackendOptions;
|
|
117
|
+
}): Promise<string>;
|
|
118
|
+
interface WatchPluginOptions {
|
|
119
|
+
/** Package root: the directory holding `tego.plugin.json`. */
|
|
120
|
+
root: string;
|
|
121
|
+
/** Port for the local bundle server. Defaults to 5180. */
|
|
122
|
+
port?: number;
|
|
123
|
+
frontend?: PackPluginOptions['frontend'];
|
|
124
|
+
log?: PackPluginOptions['log'];
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Rebuild the frontend part on change and serve it over HTTP.
|
|
128
|
+
*
|
|
129
|
+
* The loop this replaces is pack → upload → install → refresh, which is a
|
|
130
|
+
* minute per one-line change. With this running and
|
|
131
|
+
* `VITE_TEGO_LOCAL_PLUGINS=<id>=http://localhost:5180/index.js` set on the
|
|
132
|
+
* shell, saving a file rebuilds the bundle and reloads the plugin page.
|
|
133
|
+
*
|
|
134
|
+
* **No module-level HMR.** State inside the plugin page is lost on every
|
|
135
|
+
* rebuild. Hot replacement across the SystemJS boundary would mean unmounting
|
|
136
|
+
* the plugin's own React root and re-registering shared modules, which is a
|
|
137
|
+
* lot of machinery for something that would silently desync; a reload takes
|
|
138
|
+
* about a second and is always right.
|
|
139
|
+
*
|
|
140
|
+
* Frontend only. The backend runs on the host through
|
|
141
|
+
* `run-plugin-backend-locally.ts`, and the claw part runs inside a container
|
|
142
|
+
* that has to be given a new bundle either way.
|
|
143
|
+
*
|
|
144
|
+
* Never resolves — the caller is a foreground command the author interrupts.
|
|
145
|
+
*/
|
|
146
|
+
declare function watchPluginFrontend(options: WatchPluginOptions): Promise<never>;
|
|
147
|
+
interface BuildPluginBackendOptions {
|
|
148
|
+
/** Package root: the directory holding `tego.plugin.json`. */
|
|
149
|
+
root: string;
|
|
150
|
+
/**
|
|
151
|
+
* Where to write, using the part's own layout — the entry lands at
|
|
152
|
+
* `<outDir>/<part.entryPath>`, migrations and the `type: module` marker
|
|
153
|
+
* beside it. In a pack this is the staging dir; the local dev runner points
|
|
154
|
+
* it straight at its scratch dir and skips the zip entirely.
|
|
155
|
+
*/
|
|
156
|
+
outDir: string;
|
|
157
|
+
/** Source entry, relative to root. Defaults to `<dir>/src/index.ts`. */
|
|
158
|
+
entry?: string;
|
|
159
|
+
/** Extra modules to leave unbundled, on top of the built-in list. */
|
|
160
|
+
external?: string[];
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Build one plugin's backend the way the packer does — one definition of the
|
|
164
|
+
* externals, the target and the emitted `package.json`, so the local dev
|
|
165
|
+
* rebuild loop cannot drift from what a release actually ships.
|
|
166
|
+
*/
|
|
167
|
+
declare function buildPluginBackend(part: ResolvedBackendPart, options: BuildPluginBackendOptions): Promise<void>;
|
|
168
|
+
|
|
169
|
+
export { type BuildPluginBackendOptions, type PackPluginOptions, type PackedPlugin, type WatchPluginOptions, buildAgentTemplate, buildPluginBackend, buildPluginTemplates, lockPlugin, packPlugin, watchPluginFrontend };
|
package/dist/pack.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export{buildAgentTemplate,buildPluginBackend,buildPluginTemplates,lockPlugin,packPlugin,watchPluginFrontend}from"./chunk-3KUOBGJN.js";import"./chunk-7K37PVGV.js";import"./chunk-5CU33JVY.js";import"./chunk-BTHXQWHT.js";import"./chunk-7XHF3YSK.js";import"./chunk-VMCGDDGP.js";import"./chunk-SNUCO2MK.js";
|
package/dist/publish.cjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";var $=Object.defineProperty;var s=(e,a)=>$(e,"name",{value:a,configurable:!0});var chunkTHMWRUAT_cjs=require("./chunk-THMWRUAT.cjs");require("./chunk-W7C357A6.cjs"),require("./chunk-3WA3M347.cjs");var chunkROFUQLOZ_cjs=require("./chunk-ROFUQLOZ.cjs");require("./chunk-C2OCOPZQ.cjs"),require("./chunk-AJY7ZHXK.cjs"),require("./chunk-OP64Y4IN.cjs");var promises=require("fs/promises"),path=require("path"),API_PREFIX="/api/v1/tego-os";async function publishPlugin(e){const a=e.log===null?()=>{}:e.log??(t=>console.log(t)),n=await chunkTHMWRUAT_cjs.packPlugin({root:e.root,log:a});return publishPackedPlugin(n,e)}s(publishPlugin,"publishPlugin");async function publishPackedPlugin(e,a){const n=a.log===null?()=>{}:a.log??(p=>console.log(p)),t=a.fetchImpl??fetch,r=createCaller(a.server,a.token,t),u=await promises.readFile(e.file),o=path.basename(e.file);n("\u203A presigning upload");const c=await r("POST","/admin/runtime-plugins/presign-stream",{filename:o,mimeType:"application/zip",size:u.byteLength});n(`\u203A uploading ${o} (${u.byteLength} bytes)`),await putArchive(a.server,c.uploadUrl,u,t),n("\u203A inspecting package");const l=await r("POST","/admin/runtime-plugins/inspect",{uploadToken:c.uploadToken});n(` ${l.pluginId}@${l.semanticVersion} \u2014 ${describeParts(l)}${l.isUpgrade?" (upgrade)":""}${l.requiresConfig?", needs config":""}`),n("\u203A finalizing release");const g=await r("POST","/admin/runtime-plugins/upload",{uploadToken:c.uploadToken,...a.meta});let i=g.release;n(` release ${i.id} (${i.status})`),(a.approve??!0)&&(n("\u203A approving release"),i=await r("POST",`/admin/runtime-plugins/releases/${encodeURIComponent(i.id)}/approve`,{}),n(` release ${i.id} (${i.status})`));let d=null;if(a.install??!0){const p=chunkROFUQLOZ_cjs.resolvePluginScope(e.manifest),f=p==="avatar"?{releaseId:i.id,avatarIds:a.avatarIds??[]}:{releaseId:i.id};n(`\u203A installing for tenant (${p}-scoped)`),d=await r("POST","/admin/runtime-plugins/installs",f),reportInstall(d,n)}return{packed:e,preview:l,catalog:g.catalog,release:i,install:d}}s(publishPackedPlugin,"publishPackedPlugin");function describeParts(e){const a=[];return e.parts.frontend&&a.push(`frontend (${e.parts.frontend.locales.length} locales)`),e.parts.backend&&a.push(`backend (${e.parts.backend.migrationCount} migrations)`),e.parts.claw&&a.push("claw"),a.join(", ")||"no parts"}s(describeParts,"describeParts");function reportInstall(e,a){const n=e.avatars;if(!n||n.attempted===0){a(` installed ${e.pluginId}@${e.version}`);return}const t=n.attempted-n.failures.length;a(` installed ${e.pluginId}@${e.version} \u2014 ${t}/${n.attempted} avatars`);for(const r of n.failures)a(` \u2717 ${r.avatarId}: ${r.message}`)}s(reportInstall,"reportInstall");function createCaller(e,a,n){const t=e.replace(/\/+$/,"");return s(async function(u,o,c){const l=await n(`${t}${API_PREFIX}${o}`,{method:u,headers:{authorization:`Bearer ${a}`,...c===void 0?{}:{"content-type":"application/json"}},...c===void 0?{}:{body:JSON.stringify(c)}});return unwrap(l,`${u} ${o}`)},"call")}s(createCaller,"createCaller");async function putArchive(e,a,n,t){const r=e.replace(/\/+$/,""),u=await t(`${r}${a}`,{method:"PUT",headers:{"content-type":"application/zip"},body:n});await unwrap(u,"PUT upload")}s(putArchive,"putArchive");async function unwrap(e,a){let n;try{n=await e.json()}catch{n=null}if(!e.ok||!n?.success){const t=n?.error?.message??`HTTP ${e.status}`;throw new Error(`${a} failed: ${t}`)}return n.data}s(unwrap,"unwrap"),exports.publishPackedPlugin=publishPackedPlugin,exports.publishPlugin=publishPlugin;
|