@zhama/tego-plugin-sdk 1.36.0 → 1.36.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/dev.d.cts ADDED
@@ -0,0 +1,108 @@
1
+ import { IncomingMessage, ServerResponse } from 'node:http';
2
+ import { P as PluginNavEntry } from './manifest-types-CUTNfJTa.cjs';
3
+
4
+ /** `tego_dev_<id>` with every character Postgres would need quoted folded to `_`. */
5
+ declare function devSchemaName(pluginId: string): string;
6
+ /**
7
+ * The database URL the backend gets: the developer's, with the schema pinned
8
+ * as the only `search_path` entry (percent-encoded by hand, as the host does:
9
+ * libpq reads a `+` literally).
10
+ */
11
+ declare function devDatabaseUrl(databaseUrl: string, schema: string): string;
12
+ /** Applies the files not yet in the ledger, in name order; returns their names. */
13
+ declare function applyDevMigrations(options: {
14
+ databaseUrl: string;
15
+ schema: string;
16
+ migrationsDir: string;
17
+ tenantId: string;
18
+ }): Promise<string[]>;
19
+
20
+ /** Who the preview shell says is calling; sent by the shell on every API request. */
21
+ declare const DEV_USER_HEADER = "x-tego-dev-user-id";
22
+ declare const DEV_ROLES_HEADER = "x-tego-dev-roles";
23
+ declare const DEV_TENANT_ID = "dev-tenant";
24
+ interface DevCaller {
25
+ userId: string;
26
+ roles: string[];
27
+ }
28
+ /** The caller the shell named, falling back to the default dev user; never throws. */
29
+ declare function devCallerOf(headers: Record<string, string | string[] | undefined>): DevCaller;
30
+ /**
31
+ * Request headers for the backend: the browser's, minus anything that could
32
+ * pass for identity (cookies, authorization, every `x-tego-*`), plus the
33
+ * signed context `serveBackend` verifies.
34
+ */
35
+ declare function gatewayHeaders(incoming: Record<string, string | string[] | undefined>, caller: DevCaller, key: string, nowMs?: number): Record<string, string>;
36
+
37
+ interface FakeHostOptions {
38
+ token: string;
39
+ storageDir: string;
40
+ /** Backend config values, defaults applied. */
41
+ config: () => Record<string, unknown>;
42
+ /** The preview's origin, for signed URLs. */
43
+ origin: () => string;
44
+ /** Users the preview has made calls as, with the roles they had. */
45
+ users: () => ReadonlyMap<string, string[]>;
46
+ log(line: string): void;
47
+ }
48
+ /** A storage key as a file below the storage dir; refuses `..` and absolute keys. */
49
+ declare function storagePath(storageDir: string, key: string): string;
50
+ /** Handles a request below {@link FAKE_HOST_PREFIX} or {@link FAKE_FILES_PREFIX}. */
51
+ declare function handleFakeHost(req: IncomingMessage, res: ServerResponse, options: FakeHostOptions): Promise<void>;
52
+
53
+ /**
54
+ * The page the local preview serves: a small stand-in for the shell's plugin
55
+ * page, written into the plugin's `.tego-dev/shell/` on every start.
56
+ *
57
+ * Written into the plugin rather than served from this package so that its
58
+ * imports (`react`, `@tego/ui`, `react-i18next`) resolve to the plugin's own
59
+ * installed copies — the same single instances the plugin's code imports, as
60
+ * in the shell, where they are shared rather than bundled twice.
61
+ *
62
+ * It mounts the plugin's source entry with a `PluginHostContext` built the
63
+ * way the shell builds one: `basePath` `/p/<id>`, history-backed routing,
64
+ * `ctx.api` at `/api/v1/tego-os/plugin-api/<id>/*`, the frontend config's
65
+ * defaults. What only the platform has (`ai`, `office`, live events) is
66
+ * absent or inert. The top bar switches page, language, theme and the user
67
+ * the API calls are made as.
68
+ */
69
+
70
+ interface ShellOptions {
71
+ pluginId: string;
72
+ displayName: string;
73
+ nav: PluginNavEntry[];
74
+ config: Record<string, unknown>;
75
+ /** Import specifier of the plugin's source entry, relative to the shell dir; none without a frontend. */
76
+ entry?: string | undefined;
77
+ /** Locales the plugin ships (`en.json` → `en`). */
78
+ locales: string[];
79
+ }
80
+ interface ShellFile {
81
+ path: string;
82
+ contents: string;
83
+ }
84
+ declare function shellFiles(options: ShellOptions): ShellFile[];
85
+
86
+ /** First port tried; the next free one is taken when it is busy. */
87
+ declare const DEFAULT_DEV_PORT = 5280;
88
+ /** The line tools (Tego Studio) wait for; the JSON after it is `{ "url" }`. */
89
+ declare const DEV_READY_PREFIX = "TEGO_DEV_READY ";
90
+ declare const DEV_DIR = ".tego-dev";
91
+ interface DevServerOptions {
92
+ /** The plugin folder (holding tego.plugin.json). */
93
+ root: string;
94
+ /** 0 for any free port; defaults to {@link DEFAULT_DEV_PORT} or the next free one. */
95
+ port?: number;
96
+ host?: string;
97
+ /** Run the backend part (needs `databaseUrl`); default true. */
98
+ backend?: boolean;
99
+ databaseUrl?: string;
100
+ log?(line: string): void;
101
+ }
102
+ interface DevServer {
103
+ url: string;
104
+ close(): Promise<void>;
105
+ }
106
+ declare function startDevServer(options: DevServerOptions): Promise<DevServer>;
107
+
108
+ export { DEFAULT_DEV_PORT, DEV_DIR, DEV_READY_PREFIX, DEV_ROLES_HEADER, DEV_TENANT_ID, DEV_USER_HEADER, type DevServer, type DevServerOptions, applyDevMigrations, devCallerOf, devDatabaseUrl, devSchemaName, gatewayHeaders, handleFakeHost, shellFiles, startDevServer, storagePath };
package/dist/dev.d.ts ADDED
@@ -0,0 +1,108 @@
1
+ import { IncomingMessage, ServerResponse } from 'node:http';
2
+ import { P as PluginNavEntry } from './manifest-types-CUTNfJTa.js';
3
+
4
+ /** `tego_dev_<id>` with every character Postgres would need quoted folded to `_`. */
5
+ declare function devSchemaName(pluginId: string): string;
6
+ /**
7
+ * The database URL the backend gets: the developer's, with the schema pinned
8
+ * as the only `search_path` entry (percent-encoded by hand, as the host does:
9
+ * libpq reads a `+` literally).
10
+ */
11
+ declare function devDatabaseUrl(databaseUrl: string, schema: string): string;
12
+ /** Applies the files not yet in the ledger, in name order; returns their names. */
13
+ declare function applyDevMigrations(options: {
14
+ databaseUrl: string;
15
+ schema: string;
16
+ migrationsDir: string;
17
+ tenantId: string;
18
+ }): Promise<string[]>;
19
+
20
+ /** Who the preview shell says is calling; sent by the shell on every API request. */
21
+ declare const DEV_USER_HEADER = "x-tego-dev-user-id";
22
+ declare const DEV_ROLES_HEADER = "x-tego-dev-roles";
23
+ declare const DEV_TENANT_ID = "dev-tenant";
24
+ interface DevCaller {
25
+ userId: string;
26
+ roles: string[];
27
+ }
28
+ /** The caller the shell named, falling back to the default dev user; never throws. */
29
+ declare function devCallerOf(headers: Record<string, string | string[] | undefined>): DevCaller;
30
+ /**
31
+ * Request headers for the backend: the browser's, minus anything that could
32
+ * pass for identity (cookies, authorization, every `x-tego-*`), plus the
33
+ * signed context `serveBackend` verifies.
34
+ */
35
+ declare function gatewayHeaders(incoming: Record<string, string | string[] | undefined>, caller: DevCaller, key: string, nowMs?: number): Record<string, string>;
36
+
37
+ interface FakeHostOptions {
38
+ token: string;
39
+ storageDir: string;
40
+ /** Backend config values, defaults applied. */
41
+ config: () => Record<string, unknown>;
42
+ /** The preview's origin, for signed URLs. */
43
+ origin: () => string;
44
+ /** Users the preview has made calls as, with the roles they had. */
45
+ users: () => ReadonlyMap<string, string[]>;
46
+ log(line: string): void;
47
+ }
48
+ /** A storage key as a file below the storage dir; refuses `..` and absolute keys. */
49
+ declare function storagePath(storageDir: string, key: string): string;
50
+ /** Handles a request below {@link FAKE_HOST_PREFIX} or {@link FAKE_FILES_PREFIX}. */
51
+ declare function handleFakeHost(req: IncomingMessage, res: ServerResponse, options: FakeHostOptions): Promise<void>;
52
+
53
+ /**
54
+ * The page the local preview serves: a small stand-in for the shell's plugin
55
+ * page, written into the plugin's `.tego-dev/shell/` on every start.
56
+ *
57
+ * Written into the plugin rather than served from this package so that its
58
+ * imports (`react`, `@tego/ui`, `react-i18next`) resolve to the plugin's own
59
+ * installed copies — the same single instances the plugin's code imports, as
60
+ * in the shell, where they are shared rather than bundled twice.
61
+ *
62
+ * It mounts the plugin's source entry with a `PluginHostContext` built the
63
+ * way the shell builds one: `basePath` `/p/<id>`, history-backed routing,
64
+ * `ctx.api` at `/api/v1/tego-os/plugin-api/<id>/*`, the frontend config's
65
+ * defaults. What only the platform has (`ai`, `office`, live events) is
66
+ * absent or inert. The top bar switches page, language, theme and the user
67
+ * the API calls are made as.
68
+ */
69
+
70
+ interface ShellOptions {
71
+ pluginId: string;
72
+ displayName: string;
73
+ nav: PluginNavEntry[];
74
+ config: Record<string, unknown>;
75
+ /** Import specifier of the plugin's source entry, relative to the shell dir; none without a frontend. */
76
+ entry?: string | undefined;
77
+ /** Locales the plugin ships (`en.json` → `en`). */
78
+ locales: string[];
79
+ }
80
+ interface ShellFile {
81
+ path: string;
82
+ contents: string;
83
+ }
84
+ declare function shellFiles(options: ShellOptions): ShellFile[];
85
+
86
+ /** First port tried; the next free one is taken when it is busy. */
87
+ declare const DEFAULT_DEV_PORT = 5280;
88
+ /** The line tools (Tego Studio) wait for; the JSON after it is `{ "url" }`. */
89
+ declare const DEV_READY_PREFIX = "TEGO_DEV_READY ";
90
+ declare const DEV_DIR = ".tego-dev";
91
+ interface DevServerOptions {
92
+ /** The plugin folder (holding tego.plugin.json). */
93
+ root: string;
94
+ /** 0 for any free port; defaults to {@link DEFAULT_DEV_PORT} or the next free one. */
95
+ port?: number;
96
+ host?: string;
97
+ /** Run the backend part (needs `databaseUrl`); default true. */
98
+ backend?: boolean;
99
+ databaseUrl?: string;
100
+ log?(line: string): void;
101
+ }
102
+ interface DevServer {
103
+ url: string;
104
+ close(): Promise<void>;
105
+ }
106
+ declare function startDevServer(options: DevServerOptions): Promise<DevServer>;
107
+
108
+ export { DEFAULT_DEV_PORT, DEV_DIR, DEV_READY_PREFIX, DEV_ROLES_HEADER, DEV_TENANT_ID, DEV_USER_HEADER, type DevServer, type DevServerOptions, applyDevMigrations, devCallerOf, devDatabaseUrl, devSchemaName, gatewayHeaders, handleFakeHost, shellFiles, startDevServer, storagePath };
package/dist/dev.js ADDED
@@ -0,0 +1,275 @@
1
+ var Ne=Object.defineProperty;var o=(e,t)=>Ne(e,"name",{value:t,configurable:!0});import{signPluginContext as Pe}from"./chunk-WLTASJF6.js";import{readManifest as $e,readPluginLocales as Oe,buildPluginBackend as Re}from"./chunk-P2Q2AKWP.js";import"./chunk-7K37PVGV.js";import{applyConfigDefaults as se}from"./chunk-2ORO36BY.js";import"./chunk-5CU33JVY.js";import{resolvePluginParts as Le}from"./chunk-BTHXQWHT.js";import"./chunk-7XHF3YSK.js";import{PLUGIN_CONTEXT_HEADERS as D}from"./chunk-QKSPPMVN.js";import"./chunk-VMCGDDGP.js";import"./chunk-SNUCO2MK.js";import{randomUUID as Ue,randomBytes as oe,createHash as Ce}from"crypto";import{existsSync as H,realpathSync as Be,watch as Ve}from"fs";import{readdir as He,readFile as M,mkdir as W,copyFile as ie,rm as X,writeFile as Y,stat as Me}from"fs/promises";import{createServer as Fe,request as je}from"http";import{createRequire as Ge}from"module";import{join as y,resolve as T,isAbsolute as Ke,sep as ce,dirname as N,relative as le}from"path";import{spawn as Je}from"child_process";import{createServer as ze}from"net";var q="x-tego-dev-user-id",Q="x-tego-dev-roles",P="dev-tenant",ue="00000000-0000-4000-8000-000000000001";function de(e){const t=o(a=>(Array.isArray(a)?a[0]:a)?.trim()??"","single"),n=t(e[q])||ue;let r=[];try{const a=JSON.parse(t(e[Q])||"[]");Array.isArray(a)&&(r=a.filter(i=>typeof i=="string"))}catch{}return{userId:n,roles:r}}o(de,"devCallerOf");function ge(e,t,n,r=Date.now()){const a={};for(const[s,c]of Object.entries(e)){const u=s.toLowerCase();c===void 0||u.startsWith("x-tego-")||u==="cookie"||u==="authorization"||u==="host"||u==="connection"||(a[u]=Array.isArray(c)?c.join(", "):c)}const i=JSON.stringify(t.roles),l=String(r);return a[D.userId]=t.userId,a[D.tenantId]=P,a[D.roles]=i,a[D.issuedAt]=l,a[D.signature]=Pe({userId:t.userId,tenantId:P,rolesHeader:i,avatarId:"",issuedAt:l},n),a}o(ge,"gatewayHeaders");var We="tego_dev_migrations";function pe(e){return`tego_dev_${e.toLowerCase().replace(/[^a-z0-9_]/g,"_")}`.slice(0,63)}o(pe,"devSchemaName");function fe(e,t){const n=new URL(e);n.searchParams.delete("options");const r=n.search.replace(/^\?/,"");return n.search=`?${r?`${r}&`:""}options=${encodeURIComponent(`-c search_path=${t}`)}`,n.toString()}o(fe,"devDatabaseUrl");async function Xe(e){let t;try{t=await import("pg")}catch(a){throw new Error(`The local backend needs the "pg" driver; add it to the plugin's dependencies.`,{cause:a})}const n=t.default?.Client??t.Client;if(!n)throw new Error('The "pg" module has no Client constructor.');const r=new n({connectionString:e});try{await r.connect()}catch(a){throw new Error(`Cannot connect to DATABASE_URL (${Z(e)}): ${a instanceof Error?a.message:String(a)}`,{cause:a})}return r}o(Xe,"connect");function Z(e){try{const t=new URL(e);return t.password&&(t.password="***"),t.toString()}catch{return"<unparseable DATABASE_URL>"}}o(Z,"redactUrl");var he=o(e=>`"${e.replace(/"/g,'""')}"`,"quote");async function me(e){const t=await He(e.migrationsDir).then(i=>i.filter(l=>l.endsWith(".sql")).sort(),i=>{if(i.code==="ENOENT")return[];throw i}),n=await Xe(e.databaseUrl),r=he(e.schema),a=`${r}.${he(We)}`;try{await n.query(`CREATE SCHEMA IF NOT EXISTS ${r}`),await n.query(`CREATE TABLE IF NOT EXISTS ${a} (name text PRIMARY KEY, applied_at timestamptz NOT NULL DEFAULT now())`);const i=new Set((await n.query(`SELECT name FROM ${a}`)).rows.map(s=>String(s.name))),l=[];for(const s of t){if(i.has(s))continue;const c=await M(y(e.migrationsDir,s),"utf8");await n.query("BEGIN");try{await n.query(`SET LOCAL search_path TO ${r}`),await n.query("SELECT set_config('app.tenant_id', $1, true)",[e.tenantId]),await n.query(c),await n.query(`INSERT INTO ${a} (name) VALUES ($1)`,[s]),await n.query("COMMIT")}catch(u){throw await n.query("ROLLBACK").catch(()=>{}),new Error(`Migration ${s} failed: ${u instanceof Error?u.message:String(u)}`,{cause:u})}l.push(s)}return l}finally{await n.end().catch(()=>{})}}o(me,"applyDevMigrations");var Ye=250,qe=5e3;function Qe(){return new Promise((e,t)=>{const n=ze();n.once("error",t),n.listen(0,"127.0.0.1",()=>{const r=n.address(),a=typeof r=="object"&&r?r.port:0;n.close(()=>e(a))})})}o(Qe,"freePort");function ye(e){return!e||e.exitCode!==null||e.signalCode!==null?Promise.resolve():new Promise(t=>{const n=setTimeout(()=>{e.kill("SIGKILL"),t()},qe);e.once("exit",()=>{clearTimeout(n),t()}),e.kill("SIGTERM")})}o(ye,"stopChild");async function Ze(e){const{part:t,log:n}=e;if(t.runtime==="python")throw new Error("The local preview runs TypeScript backends only; a python backend runs through the platform.");const r=await Qe(),a=pe(e.pluginId),i=T(e.root,t.migrationsDirPath),l=y(e.outDir,t.entryPath),s={...process.env,NODE_ENV:"development",TEGO_PLUGIN_ID:e.pluginId,TEGO_PLUGIN_VERSION:e.version,TEGO_PLUGIN_INSTALL_ID:"dev-install",TEGO_TENANT_ID:P,TEGO_PLUGIN_PORT:String(r),TEGO_PLUGIN_HEALTH_PATH:t.healthPath,TEGO_PLUGIN_HOST_API_URL:e.hostApiUrl,TEGO_PLUGIN_HOST_API_TOKEN:e.hostApiToken,TEGO_PLUGIN_GATEWAY_KEY:e.gatewayKey,DATABASE_URL:fe(e.databaseUrl,a)};let c=null,u=!1;async function p(){await X(e.outDir,{recursive:!0,force:!0}),await Re(t,{root:e.root,outDir:e.outDir});const h=await me({databaseUrl:e.databaseUrl,schema:a,migrationsDir:i,tenantId:P});for(const S of h)n(`[backend] applied migration ${S}`)}o(p,"build");function w(){const h=Je(process.execPath,[l],{env:s,stdio:["ignore","pipe","pipe"]});c=h,h.stdout?.on("data",S=>process.stdout.write(S)),h.stderr?.on("data",S=>process.stderr.write(S)),h.on("exit",S=>{c===h&&!u&&(c=null,n(`[backend] exited (code ${S??"null"}); it starts again on the next save`))})}o(w,"start"),await p(),w(),n(`[backend] ${e.pluginId} on 127.0.0.1:${r}, schema ${a} in ${Z(e.databaseUrl)}`);let v=null,m=null,A=!1;const L=o(async()=>{if(m){A=!0;return}m=(async()=>{try{await p();const h=c;c=null,await ye(h),u||(w(),n("[backend] rebuilt and restarted"))}catch(h){n(`[backend] rebuild failed, the previous build keeps running: ${h instanceof Error?h.message:String(h)}`)}})(),await m,m=null,A&&!u&&(A=!1,await L())},"rebuild"),U=[];for(const h of[t.dir,"shared"]){const S=T(e.root,h);H(S)&&U.push(Ve(S,{recursive:!0},(x,I)=>{I&&/(^|[\\/])(node_modules|dist)([\\/]|$)/.test(String(I))||(v&&clearTimeout(v),v=setTimeout(()=>void L(),Ye))}))}return{port:r,schema:a,async close(){u=!0,v&&clearTimeout(v);for(const h of U)h.close();await m,await ye(c)}}}o(Ze,"startDevBackend");var ee="/__tego/host",te="/__tego/files",et=1024*1024;async function ne(e,t=1/0){const n=[];let r=0;for await(const a of e){if(r+=a.length,r>t)throw Object.assign(new Error("body too large"),{status:413});n.push(a)}return Buffer.concat(n)}o(ne,"readBody");function f(e,t,n){if(n===void 0){e.writeHead(t),e.end();return}e.writeHead(t,{"content-type":"application/json"}),e.end(JSON.stringify(n))}o(f,"send");function ae(e,t){const n=T(e),r=T(n,t);if(!t||Ke(t)||!r.startsWith(n+ce))throw Object.assign(new Error(`invalid storage key ${JSON.stringify(t)}`),{status:400});return r}o(ae,"storagePath");var $=o(e=>`${e}.tego-meta.json`,"metaOf");async function O(e){const t=await Me(e).catch(()=>null);if(!t?.isFile())return null;const n=await M($(e),"utf8").then(r=>JSON.parse(r),()=>({}));return{size:t.size,contentType:n.contentType??null,versionTag:Ce("sha1").update(`${t.size}:${t.mtimeMs}`).digest("hex")}}o(O,"head");async function we(e,t,n){await W(N(e),{recursive:!0}),await Y(e,t),await Y($(e),JSON.stringify({contentType:n??null}))}o(we,"put");async function ve(e,t,n){const r=new URL(e.url??"/","http://preview.local");try{if(r.pathname.startsWith(te)){const s=ae(n.storageDir,r.searchParams.get("key")??""),c=await O(s);if(!c)return f(t,404);t.writeHead(200,{"content-type":c.contentType??"application/octet-stream"}),t.end(await M(s));return}if(e.headers.authorization!==`Bearer ${n.token}`)return f(t,401,{error:"bad host API token"});const a=r.pathname.slice(ee.length)||"/",i=o(async()=>JSON.parse((await ne(e,et)).toString("utf8")||"{}"),"json"),l=o(s=>ae(n.storageDir,String(s??"")),"keyFile");switch(a){case"/config":return f(t,200,{data:{values:n.config()}});case"/log":{const{level:s,message:c,fields:u}=await i();return n.log(`[backend ${String(s??"info")}] ${String(c??"")}${u?` ${JSON.stringify(u)}`:""}`),f(t,200,{data:{}})}case"/events":{const{name:s,payload:c}=await i();return n.log(`[event] ${String(s)} ${JSON.stringify(c??null)}`),f(t,200,{data:{}})}case"/notifications":return n.log(`[notification] ${JSON.stringify(await i())}`),f(t,200,{data:{id:Ue()}});case"/directory/identity":{const{userId:s}=await i(),c=n.users().get(String(s));return f(t,200,{data:{active:!!c,roleNames:c??[],memberships:[],checkedAt:new Date().toISOString()}})}case"/directory/list":{const{kind:s,search:c,ids:u}=await i(),p=typeof c=="string"?c.toLowerCase():"",w=Array.isArray(u)?new Set(u.map(String)):void 0,v=s==="users"?[...n.users().keys()].filter(m=>(!w||w.has(m))&&m.toLowerCase().includes(p)).map(m=>({id:m,displayName:m,active:!0})):[];return f(t,200,{data:{items:v,hasMore:!1}})}case"/directory/match":{const{userId:s,principals:c}=await i(),u=Array.isArray(c)?c:[];return f(t,200,{data:{active:n.users().has(String(s)),matched:u.flatMap((p,w)=>p.kind==="user"&&p.id===s?[w]:[]),checkedAt:new Date().toISOString()}})}case"/directory/validate":{const{principals:s}=await i(),c=Array.isArray(s)?s:[],u=n.users();return f(t,200,{data:{invalid:c.flatMap((p,w)=>p.kind==="user"&&u.has(String(p.id))?[]:[w])}})}case"/storage/get":case"/storage/stream":{const s=l(r.searchParams.get("key"));if(e.method==="POST"&&a==="/storage/stream")return await we(s,await ne(e),e.headers["content-type"]),f(t,200,{data:{}});const c=await O(s);if(!c)return f(t,404);let u=await M(s);const p=Number(r.searchParams.get("bytes"));Number.isFinite(p)&&p>0&&(u=u.subarray(0,p)),t.writeHead(200,{"content-type":c.contentType??"application/octet-stream"}),t.end(u);return}case"/storage/put":return await we(l(r.searchParams.get("key")),await ne(e),e.headers["content-type"]),f(t,200,{data:{}});case"/storage/head":{const s=await O(l((await i()).key));return s?f(t,200,{data:s}):f(t,404)}case"/storage/delete":{const s=l((await i()).key);return await X(s,{force:!0}),await X($(s),{force:!0}),f(t,200,{data:{}})}case"/storage/copy":{const{sourceKey:s,destinationKey:c}=await i(),u=l(s),p=l(c);return await O(u)?(await W(N(p),{recursive:!0}),await ie(u,p),await ie($(u),$(p)).catch(()=>{}),f(t,200,{data:await O(p)})):f(t,404)}case"/storage/signed-url":{const{key:s}=await i();l(s);const c=`${te}?key=${encodeURIComponent(String(s))}`;return f(t,200,{data:{url:`${n.origin()}${c}`,path:c}})}default:return n.log(`[host] ${a} is not available in local preview`),f(t,501,{error:{code:"not_available_in_preview",message:`${a} is not available in local preview`}})}}catch(a){const i=a.status??500;f(t,i,{error:{message:a instanceof Error?a.message:String(a)}})}}o(ve,"handleFakeHost");var Se="@tego/plugin-sdk",tt=JSON.stringify(Se),nt=JSON.stringify(`${Se}/frontend`);function Ee(e){return[{path:"index.html",contents:rt(e)},{path:"main.tsx",contents:it(e)},{path:"shell.css",contents:st},{path:"plugin-surface.tsx",contents:ot}]}o(Ee,"shellFiles");var at=o(e=>e.replace(/[&<>"]/g,t=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;"})[t]),"escapeHtml");function rt({displayName:e}){return`<!doctype html>
2
+ <html lang="en" class="h-full">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>${at(e)} \xB7 local preview</title>
7
+ </head>
8
+ <body class="h-full">
9
+ <div id="tego-dev-bar"></div>
10
+ <div id="tego-dev-plugin"></div>
11
+ <script type="module" src="/main.tsx"><\/script>
12
+ </body>
13
+ </html>
14
+ `}o(rt,"indexHtml");var st=`@tailwind base;
15
+ @tailwind components;
16
+ @tailwind utilities;
17
+
18
+ html,
19
+ body {
20
+ height: 100%;
21
+ }
22
+
23
+ body {
24
+ display: flex;
25
+ flex-direction: column;
26
+ @apply bg-background text-foreground antialiased;
27
+ }
28
+
29
+ #tego-dev-plugin {
30
+ flex: 1;
31
+ min-height: 0;
32
+ overflow: auto;
33
+ }
34
+ `,ot=`import type { ReactNode } from 'react';
35
+
36
+ function Unavailable(): ReactNode {
37
+ return (
38
+ <div className='flex h-full items-center justify-center p-6 text-sm text-muted-foreground'>
39
+ Chat is not available in local preview.
40
+ </div>
41
+ );
42
+ }
43
+
44
+ export const ChatSurface = Unavailable;
45
+ export const ChatPanel = Unavailable;
46
+ export function useTopic() {
47
+ return { topic: undefined, topics: [], loading: false };
48
+ }
49
+ `;function it(e){const t=JSON.stringify({pluginId:e.pluginId,displayName:e.displayName,nav:e.nav.map(r=>({key:r.key,labelKey:r.labelKey,path:r.path??"/"})),config:e.config,locales:e.locales,userHeader:q,rolesHeader:Q,defaultUser:ue},null,2),n=e.entry?`import plugin from ${JSON.stringify(e.entry)};`:"const plugin = undefined;";return`// Generated by \`tego-plugin dev\` on every start; edits here are overwritten.
50
+ import '@tego/ui/styles/tokens.css';
51
+ import './shell.css';
52
+
53
+ import { pluginI18nNamespace } from ${tt};
54
+ import type { PluginFrontendModule, PluginHostContext, PluginRoute } from ${nt};
55
+ import {
56
+ Button,
57
+ Input,
58
+ Select,
59
+ SelectContent,
60
+ SelectItem,
61
+ SelectTrigger,
62
+ SelectValue,
63
+ Toaster,
64
+ TooltipProvider,
65
+ } from '@tego/ui';
66
+ import i18next from 'i18next';
67
+ import { useState, useSyncExternalStore } from 'react';
68
+ import { createRoot } from 'react-dom/client';
69
+ import { initReactI18next } from 'react-i18next';
70
+
71
+ ${n}
72
+
73
+ const DEV = ${t};
74
+ const BASE = '/p/' + DEV.pluginId;
75
+ const NAMESPACE = pluginI18nNamespace(DEV.pluginId);
76
+
77
+ function stored(key: string, fallback: string): string {
78
+ try {
79
+ return localStorage.getItem('tegoDev.' + key) ?? fallback;
80
+ } catch {
81
+ return fallback;
82
+ }
83
+ }
84
+ function store(key: string, value: string): void {
85
+ try {
86
+ localStorage.setItem('tegoDev.' + key, value);
87
+ } catch {
88
+ // storage blocked: the choice lasts until the next reload
89
+ }
90
+ }
91
+
92
+ const user = {
93
+ userId: stored('userId', DEV.defaultUser),
94
+ roles: stored('roles', '').split(',').map(role => role.trim()).filter(Boolean),
95
+ };
96
+ const language = DEV.locales.includes(stored('lang', 'zh-CN')) ? stored('lang', 'zh-CN') : (DEV.locales[0] ?? 'en');
97
+ if (stored('theme', 'light') === 'dark') document.documentElement.classList.add('dark');
98
+
99
+ async function loadLocale(tag: string): Promise<void> {
100
+ if (i18next.hasResourceBundle(tag, NAMESPACE)) return;
101
+ const response = await fetch('/i18n/' + tag + '.json');
102
+ if (response.ok) i18next.addResourceBundle(tag, NAMESPACE, await response.json(), true, true);
103
+ }
104
+ await i18next.use(initReactI18next).init({
105
+ lng: language,
106
+ fallbackLng: false,
107
+ ns: [NAMESPACE],
108
+ defaultNS: NAMESPACE,
109
+ resources: {},
110
+ interpolation: { escapeValue: false },
111
+ });
112
+ await loadLocale(language);
113
+
114
+ const listeners = new Set<() => void>();
115
+ function readRoute(): PluginRoute {
116
+ const path = location.pathname.slice(BASE.length) || '/';
117
+ return { path: path.startsWith('/') ? path : '/' + path, search: location.search };
118
+ }
119
+ let route = readRoute();
120
+ function routeChanged(): void {
121
+ const next = readRoute();
122
+ if (next.path === route.path && next.search === route.search) return;
123
+ route = next;
124
+ for (const listener of listeners) listener();
125
+ }
126
+ addEventListener('popstate', routeChanged);
127
+ if (!location.pathname.startsWith(BASE)) history.replaceState(null, '', BASE + '/');
128
+
129
+ function navigate(to: string): void {
130
+ history.pushState(null, '', to.startsWith('/p/') ? to : BASE + (to.startsWith('/') ? to : '/' + to));
131
+ routeChanged();
132
+ }
133
+
134
+ const api: PluginHostContext['api'] = {
135
+ request: (path, init = {}) =>
136
+ fetch('/api/v1/tego-os/plugin-api/' + DEV.pluginId + (path.startsWith('/') ? path : '/' + path), {
137
+ ...init,
138
+ headers: {
139
+ ...(init.headers as Record<string, string> | undefined),
140
+ [DEV.userHeader]: user.userId,
141
+ [DEV.rolesHeader]: JSON.stringify(user.roles),
142
+ },
143
+ }),
144
+ async json<T>(path: string, init?: RequestInit): Promise<T> {
145
+ const response = await api.request(path, init);
146
+ if (!response.ok) throw new Error((init?.method ?? 'GET') + ' ' + path + ': ' + response.status);
147
+ return (await response.json()) as T;
148
+ },
149
+ };
150
+
151
+ const navKeys = DEV.nav.map(entry => entry.key);
152
+ const context: PluginHostContext = {
153
+ pluginId: DEV.pluginId,
154
+ layout: { collapseSidebar: () => () => {} },
155
+ basePath: BASE,
156
+ publicPagesUrl: location.origin + '/public/' + DEV.pluginId + '/',
157
+ hostUrl: path => new URL(path, location.origin).toString(),
158
+ user: { userId: user.userId, tenantId: 'dev-tenant', roles: user.roles, displayName: user.userId },
159
+ api,
160
+ route: {
161
+ current: () => route,
162
+ subscribe: listener => {
163
+ listeners.add(listener);
164
+ return () => listeners.delete(listener);
165
+ },
166
+ },
167
+ events: { subscribe: () => () => {}, connected: () => false, subscribeStatus: () => () => {} },
168
+ config: DEV.config,
169
+ navigate,
170
+ can: navKey => navKeys.includes(navKey),
171
+ };
172
+
173
+ function useRoute(): PluginRoute {
174
+ return useSyncExternalStore(context.route.subscribe, context.route.current);
175
+ }
176
+
177
+ function DevBar() {
178
+ const current = useRoute();
179
+ const [lang, setLang] = useState(language);
180
+ const [dark, setDark] = useState(document.documentElement.classList.contains('dark'));
181
+ const [userId, setUserId] = useState(user.userId);
182
+ const [roles, setRoles] = useState(user.roles.join(', '));
183
+ const switchUser = () => {
184
+ store('userId', userId.trim() || DEV.defaultUser);
185
+ store('roles', roles);
186
+ location.reload();
187
+ };
188
+ return (
189
+ <div className='flex shrink-0 items-center gap-2 border-b border-border bg-card px-3 py-2 text-sm'>
190
+ <span className='shrink-0 font-medium'>{DEV.displayName}</span>
191
+ <span className='shrink-0 rounded-control bg-sunken px-1.5 py-0.5 font-mono text-xs text-muted-foreground'>preview</span>
192
+ <nav className='flex min-w-0 flex-1 items-center gap-1 overflow-x-auto'>
193
+ {DEV.nav.map(entry => (
194
+ <Button
195
+ key={entry.key}
196
+ size='sm'
197
+ variant={current.path === entry.path ? 'secondary' : 'ghost'}
198
+ onClick={() => navigate(entry.path)}
199
+ >
200
+ {i18next.t(entry.labelKey, { ns: NAMESPACE, lng: lang })}
201
+ </Button>
202
+ ))}
203
+ </nav>
204
+ <Select
205
+ value={lang}
206
+ onValueChange={async next => {
207
+ await loadLocale(next);
208
+ await i18next.changeLanguage(next);
209
+ store('lang', next);
210
+ setLang(next);
211
+ }}
212
+ >
213
+ <SelectTrigger className='h-8 w-28' aria-label='Language'>
214
+ <SelectValue />
215
+ </SelectTrigger>
216
+ <SelectContent>
217
+ {DEV.locales.map(tag => (
218
+ <SelectItem key={tag} value={tag}>
219
+ {tag}
220
+ </SelectItem>
221
+ ))}
222
+ </SelectContent>
223
+ </Select>
224
+ <Button
225
+ size='sm'
226
+ variant='ghost'
227
+ onClick={() => {
228
+ document.documentElement.classList.toggle('dark', !dark);
229
+ store('theme', dark ? 'light' : 'dark');
230
+ setDark(!dark);
231
+ }}
232
+ >
233
+ {dark ? 'Light' : 'Dark'}
234
+ </Button>
235
+ <form
236
+ className='flex shrink-0 items-center gap-1'
237
+ onSubmit={event => {
238
+ event.preventDefault();
239
+ switchUser();
240
+ }}
241
+ >
242
+ <Input className='h-8 w-32' aria-label='User id' value={userId} onChange={event => setUserId(event.target.value)} />
243
+ <Input
244
+ className='h-8 w-36'
245
+ aria-label='Roles, comma-separated'
246
+ placeholder='roles'
247
+ value={roles}
248
+ onChange={event => setRoles(event.target.value)}
249
+ />
250
+ <Button size='sm' variant='outline' type='submit'>
251
+ Sign in as
252
+ </Button>
253
+ </form>
254
+ </div>
255
+ );
256
+ }
257
+
258
+ createRoot(document.getElementById('tego-dev-bar')!).render(
259
+ <TooltipProvider>
260
+ <DevBar />
261
+ <Toaster />
262
+ </TooltipProvider>
263
+ );
264
+
265
+ const mountPoint = document.getElementById('tego-dev-plugin')!;
266
+ const frontend = plugin as PluginFrontendModule | undefined;
267
+ if (frontend) {
268
+ frontend.mount(mountPoint, context);
269
+ } else {
270
+ mountPoint.innerHTML =
271
+ '<p style="padding:24px">This plugin has no frontend part; its API is served at /api/v1/tego-os/plugin-api/' +
272
+ DEV.pluginId +
273
+ '/</p>';
274
+ }
275
+ `}o(it,"mainTsx");var be=5280,ct=20,Ie="TEGO_DEV_READY ",Te=".tego-dev",lt="/api/v1/tego-os/plugin-api/";function ut(e){const{displayName:t}=e;return typeof t=="string"?t:t.en??t["zh-CN"]??Object.values(t)[0]??e.id}o(ut,"displayNameOf");function re(e,t){for(let n=T(e);;n=N(n)){const r=y(n,"node_modules",...t.split("/"));if(H(y(r,"package.json")))return Be(r);if(N(n)===n)return}}o(re,"packageDir");function R(e,t,n){e.writeHead(t,{"content-type":"application/json"}),e.end(JSON.stringify(n))}o(R,"sendJson");function dt(e,t,n){return new Promise((r,a)=>{const i=o(s=>{e.off("listening",l),a(s)},"onError"),l=o(()=>{e.off("error",i);const s=e.address();r(typeof s=="object"&&s?s.port:t)},"onListening");e.once("error",i),e.once("listening",l),e.listen(t,n)})}o(dt,"listen");async function gt(e,t){const n=Ge(y(e,"vite.config.ts"));let r,a;try{r=n("@tego/ui/tailwind-preset"),a=N(n.resolve("@tego/ui"))}catch(l){throw new Error(`The preview cannot load @tego/ui's Tailwind preset from ${e}: ${l instanceof Error?l.message:String(l)}. Install the plugin's dependencies.`,{cause:l})}const i=(await import("tailwindcss")).default;return i({presets:[r],content:[y(a,"**/*.{js,cjs}"),y(t,"*.tsx")]})}o(gt,"shellTailwind");function pt(e,t,n){return{postcssPlugin:"tego-dev-stylesheets",async Once(r,a){const i=r.source?.input.file,l=i&&T(i)===e?[t]:n;if(l.length===0)return;const s=await a.postcss(l).process(r,{from:i});a.result.messages.push(...s.messages)}}}o(pt,"perStylesheet");function ft(e){return Array.isArray(e)?e.flat(1/0).map(t=>{if(!t||typeof t!="object")return t;const{buildStart:n}=t;return typeof n!="function"?t:{...t,buildStart(...r){const a=new Proxy(this,{get(i,l){if(l==="emitFile")return()=>"";const s=Reflect.get(i,l);return typeof s=="function"?s.bind(i):s}});return n.apply(a,r)}}}):e}o(ft,"servePlugins");async function ht(e){const t=T(e.root),n=e.log??(d=>console.log(d)),r=await $e(t),a=Le(r),i=y(t,Te),l=y(i,"shell"),s=oe(32).toString("hex"),c=oe(24).toString("hex");let u="";const p=new Map;let w,v={};const m=a.frontend?T(t,a.frontend.dir):t,{loadConfigFromFile:A,createServer:L,mergeConfig:U}=await import("vite");if(a.frontend){const d=y(m,"vite.config.ts");H(d)&&(v=(await A({command:"serve",mode:"development"},d,t))?.config??{});const g=v.build?.rollupOptions?.input,E=T(t,typeof g=="string"?g:`${a.frontend.dir}/src/index.tsx`);if(!H(E))throw new Error(`The frontend entry ${le(t,E)} does not exist.`);w=le(l,E).split(ce).join("/"),w.startsWith(".")||(w=`./${w}`)}const h=o(()=>a.frontend?Oe(t,r,a.frontend.i18nDirPath):Promise.resolve(new Map),"localeFiles"),S=[...(await h()).keys()].map(d=>d.replace(/\.json$/,""));await W(l,{recursive:!0});for(const d of Ee({pluginId:r.id,displayName:ut(r),nav:a.frontend?.nav??[],config:a.frontend?.config?se(a.frontend.config.schema,{}):{},entry:w,locales:S}))await Y(y(l,d.path),d.contents);let x,I;const ke=o(()=>a.backend?.config?se(a.backend.config.schema,{}):{},"backendConfig"),C=Fe((d,g)=>void xe(d,g));async function xe(d,g){const E=(d.url??"/").split("?")[0];try{if(E.startsWith(ee)||E.startsWith(te)){await ve(d,g,{token:c,storageDir:y(i,"storage"),config:ke,origin:o(()=>u,"origin"),users:o(()=>p,"users"),log:n});return}const b=/^\/i18n\/([A-Za-z-]+)\.json$/.exec(E);if(b){const k=(await h()).get(`${b[1]}.json`);if(k===void 0)return R(g,404,{error:`no ${b[1]}.json`});g.writeHead(200,{"content-type":"application/json"}),g.end(k);return}const _=`${lt}${r.id}`;if(E===_||E.startsWith(`${_}/`)){_e(d,g,(d.url??"/").slice(_.length)||"/");return}j.middlewares(d,g,()=>R(g,404,{error:`${E} not found`}))}catch(b){R(g,500,{error:b instanceof Error?b.message:String(b)})}}o(xe,"route");function _e(d,g,E){if(!x){R(g,503,{error:I??"The plugin has no backend part."});return}const b=de(d.headers);p.set(b.userId,b.roles);const _=je({host:"127.0.0.1",port:x.port,method:d.method,path:E,headers:ge(d.headers,b,s)},k=>{g.writeHead(k.statusCode??502,k.headers),k.pipe(g)});_.on("error",k=>{g.headersSent?g.destroy():R(g,502,{error:`The backend is not answering (${k.message}); see the terminal.`})}),d.pipe(_)}o(_e,"proxy");const Ae=y(l,"shell.css"),De=(()=>{const d=v.css?.postcss;return d&&typeof d=="object"?d.plugins??[]:[]})(),B=(()=>{const d=re(m,"react-i18next");return(d&&re(d,"i18next"))??re(m,"i18next")})(),{css:mt,mode:yt,build:wt,...F}=v;F.plugins=ft(F.plugins);const j=await L(U(F,{configFile:!1,root:l,mode:"development",appType:"spa",clearScreen:!1,logLevel:"info",esbuild:{jsx:"automatic",jsxDev:!1},css:{postcss:{plugins:[pt(Ae,await gt(m,l),De)]}},resolve:{alias:[{find:"@tego/chat/plugin-surface",replacement:y(l,"plugin-surface.tsx")},...B?[{find:/^i18next$/,replacement:B}]:[]]},server:{middlewareMode:!0,hmr:{server:C},fs:{allow:[t,l,...B?[B]:[]]}},optimizeDeps:{entries:[y(l,"index.html")]}})),V=e.host??"127.0.0.1";let G;const K=e.port??be;for(let d=0;G===void 0;d++)try{G=await dt(C,K===0?0:K+d,V)}catch(g){if(g.code!=="EADDRINUSE"||K===0||d>=ct)throw await j.close(),g}const J=V==="0.0.0.0"||V==="::"?"127.0.0.1":V;if(u=`http://${J.includes(":")?`[${J}]`:J}:${G}`,!a.backend)I="The plugin has no backend part.";else if(e.backend===!1)I="The backend is off (--no-backend).";else if(!e.databaseUrl)I="The backend needs a PostgreSQL: start the preview with DATABASE_URL=postgres://\u2026 (each plugin gets its own schema).";else try{x=await Ze({root:t,pluginId:r.id,version:r.version,part:a.backend,databaseUrl:e.databaseUrl,outDir:y(i,"backend"),hostApiUrl:`${u}${ee}`,hostApiToken:c,gatewayKey:s,log:n})}catch(d){I=`The backend did not start: ${d instanceof Error?d.message:String(d)}`}I&&a.backend&&n(`[backend] ${I}`);const z=`${u}/p/${r.id}/`;return n(`${r.id} ${r.version}: local preview at ${z}`),e.databaseUrl&&x&&n(` database ${Z(e.databaseUrl)}, schema ${x.schema}`),n(`${Ie}${JSON.stringify({url:z})}`),{url:z,async close(){await x?.close(),await j.close(),C.closeAllConnections(),await new Promise(d=>C.close(()=>d()))}}}o(ht,"startDevServer");export{be as DEFAULT_DEV_PORT,Te as DEV_DIR,Ie as DEV_READY_PREFIX,Q as DEV_ROLES_HEADER,P as DEV_TENANT_ID,q as DEV_USER_HEADER,me as applyDevMigrations,de as devCallerOf,fe as devDatabaseUrl,pe as devSchemaName,ge as gatewayHeaders,ve as handleFakeHost,Ee as shellFiles,ht as startDevServer,ae as storagePath};
package/dist/index.cjs CHANGED
@@ -1 +1 @@
1
- "use strict";var f=Object.defineProperty;var r=(e,t)=>f(e,"name",{value:t,configurable:!0});var chunkROFUQLOZ_cjs=require("./chunk-ROFUQLOZ.cjs"),chunkC2OCOPZQ_cjs=require("./chunk-C2OCOPZQ.cjs"),PLUGIN_CONFIG_SECTIONS=["frontend","backend","claw"],PLUGIN_CONFIG_SECRET_SENTINEL="__OPENCLAW_REDACTED__",EMPTY_CONFIG_SECTION_SUMMARY={fieldCount:0,required:[],sensitive:[]};function summarizeConfigDeclaration(e){if(!e)return EMPTY_CONFIG_SECTION_SUMMARY;const t=Object.keys(e.schema.properties),n=e.uiHints??{};return{fieldCount:t.length,required:(e.schema.required??[]).filter(u=>t.includes(u)),sensitive:t.filter(u=>n[u]?.sensitive===!0)}}r(summarizeConfigDeclaration,"summarizeConfigDeclaration");function summarizeClawConfig(e){if(!e)return EMPTY_CONFIG_SECTION_SUMMARY;const t=e.configSchema;if(typeof t!="object"||t===null)return EMPTY_CONFIG_SECTION_SUMMARY;const n=t.properties,u=typeof n=="object"&&n!==null?Object.keys(n):[],i=t.required,s=Array.isArray(i)?i.filter(l=>typeof l=="string"&&u.includes(l)):[],o=e.uiHints,a=typeof o=="object"&&o!==null?o:{},c=u.filter(l=>a[l]?.sensitive===!0);return{fieldCount:u.length,required:s,sensitive:c}}r(summarizeClawConfig,"summarizeClawConfig");function redactSecrets(e,t){const n={...e};for(const u of t)n[u]===void 0||n[u]===null||(n[u]=PLUGIN_CONFIG_SECRET_SENTINEL);return n}r(redactSecrets,"redactSecrets");function restoreSecrets(e,t,n){const u={...e};for(const i of n){if(u[i]!==PLUGIN_CONFIG_SECRET_SENTINEL)continue;const s=t[i];if(s===void 0){delete u[i];continue}u[i]=s}return u}r(restoreSecrets,"restoreSecrets");function applyConfigDefaults(e,t){const n={...t};for(const[u,i]of Object.entries(e.properties??{}))n[u]===void 0&&i.default!==void 0&&(n[u]=i.default);return n}r(applyConfigDefaults,"applyConfigDefaults");function configFieldLabel(e,t,n,u){return t?.label?chunkROFUQLOZ_cjs.localizedTextToString(t.label,u):n?.title?n.title:e}r(configFieldLabel,"configFieldLabel");function readClawTools(e){if(!e)return[];const t=e.contracts;if(typeof t!="object"||t===null)return[];const n=t.tools;return Array.isArray(n)?n.filter(u=>typeof u=="string"):[]}r(readClawTools,"readClawTools");function auditDeclarationGaps(e,t){const n=Object.keys(e.audit?.tools??{}),u=new Set(t);return{undeclared:t.filter(i=>!e.audit?.tools?.[i]),unknown:n.filter(i=>!u.has(i))}}r(auditDeclarationGaps,"auditDeclarationGaps");function buildInstallDisclosure(e,t=null,n=null){const u=(e.parts.frontend?.nav??[]).map(o=>({key:o.key,labelKey:o.labelKey,permission:chunkROFUQLOZ_cjs.pluginMenuPermission(e.id,o.key),path:chunkROFUQLOZ_cjs.pluginNavPath(e.id,o.path)})),i=chunkROFUQLOZ_cjs.resolvePluginParts(e).backend,s=readClawTools(t);return{requiredPermissions:[...new Set(e.permissions?.required??[])].sort(),egress:i?.egress??[],publicRoutes:(i?.publicRoutes??[]).map(chunkROFUQLOZ_cjs.formatPublicRoute).sort(),...i?{backendRuntime:i.runtime}:{},scope:chunkROFUQLOZ_cjs.resolvePluginScope(e),parts:chunkROFUQLOZ_cjs.declaredPartNames(e),declares:chunkROFUQLOZ_cjs.resolvePluginDeclares(e),nav:u,clawTools:s,auditUndeclaredTools:auditDeclarationGaps(e,s).undeclared,config:{frontend:summarizeConfigDeclaration(e.parts.frontend?.config),backend:summarizeConfigDeclaration(e.parts.backend?.config),claw:summarizeClawConfig(t)},...n?{access:{permissions:Object.values(n.permissions).filter(o=>!o.reserved).length,roles:Object.keys(n.roles).length}}:{}}}r(buildInstallDisclosure,"buildInstallDisclosure");function requiresBackendConfig(e){return e.config.backend.required.length>0}r(requiresBackendConfig,"requiresBackendConfig");function diffInstallDisclosure(e,t){const n=[];for(const o of t.requiredPermissions??[])e?.requiredPermissions?.includes(o)||n.push({kind:"permission",value:o});for(const o of t.egress??[])!e?.egress?.includes(o)&&!e?.egress?.includes("*")&&n.push({kind:"egress",value:o});for(const o of t.publicRoutes??[])e?.publicRoutes?.includes(o)||n.push({kind:"publicRoute",value:o});const u=new Set(e?.parts??[]);for(const o of t.parts)u.has(o)||n.push({kind:"part",value:o});for(const o of["database","storage","events"])t.declares[o]&&(e?.declares[o]||n.push({kind:"declares",value:o}));const i=new Set((e?.nav??[]).map(o=>o.key));for(const o of t.nav)i.has(o.key)||n.push({kind:"nav",value:o.key});const s=new Set(e?.clawTools??[]);for(const o of t.clawTools)s.has(o)||n.push({kind:"clawTool",value:o});for(const o of["frontend","backend","claw"]){const a=new Set(e?.config[o]?.required??[]);for(const c of t.config[o].required)a.has(c)||n.push({kind:"configRequired",value:`${o}.${c}`})}return n}r(diffInstallDisclosure,"diffInstallDisclosure"),Object.defineProperty(exports,"CLAW_MANIFEST_FILENAME",{enumerable:!0,get:r(function(){return chunkROFUQLOZ_cjs.CLAW_MANIFEST_FILENAME},"get")}),Object.defineProperty(exports,"MAX_PLUGIN_MENU_PERMISSION_LENGTH",{enumerable:!0,get:r(function(){return chunkROFUQLOZ_cjs.MAX_PLUGIN_MENU_PERMISSION_LENGTH},"get")}),Object.defineProperty(exports,"PLUGIN_AVATAR_PUBLIC_API_PATH",{enumerable:!0,get:r(function(){return chunkROFUQLOZ_cjs.PLUGIN_AVATAR_PUBLIC_API_PATH},"get")}),Object.defineProperty(exports,"PLUGIN_AVATAR_PUBLIC_PAGES_PATH",{enumerable:!0,get:r(function(){return chunkROFUQLOZ_cjs.PLUGIN_AVATAR_PUBLIC_PAGES_PATH},"get")}),Object.defineProperty(exports,"PLUGIN_BACKEND_PLATFORMS",{enumerable:!0,get:r(function(){return chunkROFUQLOZ_cjs.PLUGIN_BACKEND_PLATFORMS},"get")}),Object.defineProperty(exports,"PLUGIN_BACKEND_RUNTIMES",{enumerable:!0,get:r(function(){return chunkROFUQLOZ_cjs.PLUGIN_BACKEND_RUNTIMES},"get")}),Object.defineProperty(exports,"PLUGIN_MANIFEST_FILENAME",{enumerable:!0,get:r(function(){return chunkROFUQLOZ_cjs.PLUGIN_MANIFEST_FILENAME},"get")}),Object.defineProperty(exports,"PLUGIN_NAV_ICONS",{enumerable:!0,get:r(function(){return chunkROFUQLOZ_cjs.PLUGIN_NAV_ICONS},"get")}),Object.defineProperty(exports,"PLUGIN_NAV_ICON_FALLBACK",{enumerable:!0,get:r(function(){return chunkROFUQLOZ_cjs.PLUGIN_NAV_ICON_FALLBACK},"get")}),Object.defineProperty(exports,"PLUGIN_PART_DEFAULTS",{enumerable:!0,get:r(function(){return chunkROFUQLOZ_cjs.PLUGIN_PART_DEFAULTS},"get")}),Object.defineProperty(exports,"PLUGIN_PART_NAMES",{enumerable:!0,get:r(function(){return chunkROFUQLOZ_cjs.PLUGIN_PART_NAMES},"get")}),Object.defineProperty(exports,"PLUGIN_PUBLIC_API_PATH",{enumerable:!0,get:r(function(){return chunkROFUQLOZ_cjs.PLUGIN_PUBLIC_API_PATH},"get")}),Object.defineProperty(exports,"PLUGIN_PUBLIC_PAGES_PATH",{enumerable:!0,get:r(function(){return chunkROFUQLOZ_cjs.PLUGIN_PUBLIC_PAGES_PATH},"get")}),Object.defineProperty(exports,"PLUGIN_PUBLIC_ROUTE_METHODS",{enumerable:!0,get:r(function(){return chunkROFUQLOZ_cjs.PLUGIN_PUBLIC_ROUTE_METHODS},"get")}),Object.defineProperty(exports,"PLUGIN_SUPPORTED_LOCALES",{enumerable:!0,get:r(function(){return chunkROFUQLOZ_cjs.PLUGIN_SUPPORTED_LOCALES},"get")}),Object.defineProperty(exports,"declaredPartNames",{enumerable:!0,get:r(function(){return chunkROFUQLOZ_cjs.declaredPartNames},"get")}),Object.defineProperty(exports,"formatPublicRoute",{enumerable:!0,get:r(function(){return chunkROFUQLOZ_cjs.formatPublicRoute},"get")}),Object.defineProperty(exports,"localizedTextToString",{enumerable:!0,get:r(function(){return chunkROFUQLOZ_cjs.localizedTextToString},"get")}),Object.defineProperty(exports,"matchPublicRoute",{enumerable:!0,get:r(function(){return chunkROFUQLOZ_cjs.matchPublicRoute},"get")}),Object.defineProperty(exports,"pluginApiPath",{enumerable:!0,get:r(function(){return chunkROFUQLOZ_cjs.pluginApiPath},"get")}),Object.defineProperty(exports,"pluginBasePath",{enumerable:!0,get:r(function(){return chunkROFUQLOZ_cjs.pluginBasePath},"get")}),Object.defineProperty(exports,"pluginI18nKey",{enumerable:!0,get:r(function(){return chunkROFUQLOZ_cjs.pluginI18nKey},"get")}),Object.defineProperty(exports,"pluginI18nNamespace",{enumerable:!0,get:r(function(){return chunkROFUQLOZ_cjs.pluginI18nNamespace},"get")}),Object.defineProperty(exports,"pluginMenuKey",{enumerable:!0,get:r(function(){return chunkROFUQLOZ_cjs.pluginMenuKey},"get")}),Object.defineProperty(exports,"pluginMenuPermission",{enumerable:!0,get:r(function(){return chunkROFUQLOZ_cjs.pluginMenuPermission},"get")}),Object.defineProperty(exports,"pluginNavPath",{enumerable:!0,get:r(function(){return chunkROFUQLOZ_cjs.pluginNavPath},"get")}),Object.defineProperty(exports,"publicApiBaseFromPagePath",{enumerable:!0,get:r(function(){return chunkROFUQLOZ_cjs.publicApiBaseFromPagePath},"get")}),Object.defineProperty(exports,"resolvePluginDeclares",{enumerable:!0,get:r(function(){return chunkROFUQLOZ_cjs.resolvePluginDeclares},"get")}),Object.defineProperty(exports,"resolvePluginParts",{enumerable:!0,get:r(function(){return chunkROFUQLOZ_cjs.resolvePluginParts},"get")}),Object.defineProperty(exports,"resolvePluginScope",{enumerable:!0,get:r(function(){return chunkROFUQLOZ_cjs.resolvePluginScope},"get")}),Object.defineProperty(exports,"HOST_API_VERSION",{enumerable:!0,get:r(function(){return chunkC2OCOPZQ_cjs.HOST_API_VERSION},"get")}),Object.defineProperty(exports,"SHARED_MODULE_IDS",{enumerable:!0,get:r(function(){return chunkC2OCOPZQ_cjs.SHARED_MODULE_IDS},"get")}),Object.defineProperty(exports,"hostApiRangeMinimum",{enumerable:!0,get:r(function(){return chunkC2OCOPZQ_cjs.hostApiRangeMinimum},"get")}),Object.defineProperty(exports,"isValidHostApiRange",{enumerable:!0,get:r(function(){return chunkC2OCOPZQ_cjs.isValidHostApiRange},"get")}),Object.defineProperty(exports,"satisfiesHostApiRange",{enumerable:!0,get:r(function(){return chunkC2OCOPZQ_cjs.satisfiesHostApiRange},"get")}),exports.EMPTY_CONFIG_SECTION_SUMMARY=EMPTY_CONFIG_SECTION_SUMMARY,exports.PLUGIN_CONFIG_SECRET_SENTINEL=PLUGIN_CONFIG_SECRET_SENTINEL,exports.PLUGIN_CONFIG_SECTIONS=PLUGIN_CONFIG_SECTIONS,exports.applyConfigDefaults=applyConfigDefaults,exports.auditDeclarationGaps=auditDeclarationGaps,exports.buildInstallDisclosure=buildInstallDisclosure,exports.configFieldLabel=configFieldLabel,exports.diffInstallDisclosure=diffInstallDisclosure,exports.redactSecrets=redactSecrets,exports.requiresBackendConfig=requiresBackendConfig,exports.restoreSecrets=restoreSecrets,exports.summarizeClawConfig=summarizeClawConfig,exports.summarizeConfigDeclaration=summarizeConfigDeclaration;
1
+ "use strict";var a=Object.defineProperty;var e=(t,n)=>a(t,"name",{value:n,configurable:!0});var chunkKMN5RHLX_cjs=require("./chunk-KMN5RHLX.cjs"),chunkROFUQLOZ_cjs=require("./chunk-ROFUQLOZ.cjs"),chunkC2OCOPZQ_cjs=require("./chunk-C2OCOPZQ.cjs");function readClawTools(t){if(!t)return[];const n=t.contracts;if(typeof n!="object"||n===null)return[];const u=n.tools;return Array.isArray(u)?u.filter(i=>typeof i=="string"):[]}e(readClawTools,"readClawTools");function auditDeclarationGaps(t,n){const u=Object.keys(t.audit?.tools??{}),i=new Set(n);return{undeclared:n.filter(o=>!t.audit?.tools?.[o]),unknown:u.filter(o=>!i.has(o))}}e(auditDeclarationGaps,"auditDeclarationGaps");function buildInstallDisclosure(t,n=null,u=null){const i=(t.parts.frontend?.nav??[]).map(r=>({key:r.key,labelKey:r.labelKey,permission:chunkROFUQLOZ_cjs.pluginMenuPermission(t.id,r.key),path:chunkROFUQLOZ_cjs.pluginNavPath(t.id,r.path)})),o=chunkROFUQLOZ_cjs.resolvePluginParts(t).backend,s=readClawTools(n);return{requiredPermissions:[...new Set(t.permissions?.required??[])].sort(),egress:o?.egress??[],publicRoutes:(o?.publicRoutes??[]).map(chunkROFUQLOZ_cjs.formatPublicRoute).sort(),...o?{backendRuntime:o.runtime}:{},scope:chunkROFUQLOZ_cjs.resolvePluginScope(t),parts:chunkROFUQLOZ_cjs.declaredPartNames(t),declares:chunkROFUQLOZ_cjs.resolvePluginDeclares(t),nav:i,clawTools:s,auditUndeclaredTools:auditDeclarationGaps(t,s).undeclared,config:{frontend:chunkKMN5RHLX_cjs.summarizeConfigDeclaration(t.parts.frontend?.config),backend:chunkKMN5RHLX_cjs.summarizeConfigDeclaration(t.parts.backend?.config),claw:chunkKMN5RHLX_cjs.summarizeClawConfig(n)},...u?{access:{permissions:Object.values(u.permissions).filter(r=>!r.reserved).length,roles:Object.keys(u.roles).length}}:{}}}e(buildInstallDisclosure,"buildInstallDisclosure");function requiresBackendConfig(t){return t.config.backend.required.length>0}e(requiresBackendConfig,"requiresBackendConfig");function diffInstallDisclosure(t,n){const u=[];for(const r of n.requiredPermissions??[])t?.requiredPermissions?.includes(r)||u.push({kind:"permission",value:r});for(const r of n.egress??[])!t?.egress?.includes(r)&&!t?.egress?.includes("*")&&u.push({kind:"egress",value:r});for(const r of n.publicRoutes??[])t?.publicRoutes?.includes(r)||u.push({kind:"publicRoute",value:r});const i=new Set(t?.parts??[]);for(const r of n.parts)i.has(r)||u.push({kind:"part",value:r});for(const r of["database","storage","events"])n.declares[r]&&(t?.declares[r]||u.push({kind:"declares",value:r}));const o=new Set((t?.nav??[]).map(r=>r.key));for(const r of n.nav)o.has(r.key)||u.push({kind:"nav",value:r.key});const s=new Set(t?.clawTools??[]);for(const r of n.clawTools)s.has(r)||u.push({kind:"clawTool",value:r});for(const r of["frontend","backend","claw"]){const l=new Set(t?.config[r]?.required??[]);for(const c of n.config[r].required)l.has(c)||u.push({kind:"configRequired",value:`${r}.${c}`})}return u}e(diffInstallDisclosure,"diffInstallDisclosure"),Object.defineProperty(exports,"EMPTY_CONFIG_SECTION_SUMMARY",{enumerable:!0,get:e(function(){return chunkKMN5RHLX_cjs.EMPTY_CONFIG_SECTION_SUMMARY},"get")}),Object.defineProperty(exports,"PLUGIN_CONFIG_SECRET_SENTINEL",{enumerable:!0,get:e(function(){return chunkKMN5RHLX_cjs.PLUGIN_CONFIG_SECRET_SENTINEL},"get")}),Object.defineProperty(exports,"PLUGIN_CONFIG_SECTIONS",{enumerable:!0,get:e(function(){return chunkKMN5RHLX_cjs.PLUGIN_CONFIG_SECTIONS},"get")}),Object.defineProperty(exports,"applyConfigDefaults",{enumerable:!0,get:e(function(){return chunkKMN5RHLX_cjs.applyConfigDefaults},"get")}),Object.defineProperty(exports,"configFieldLabel",{enumerable:!0,get:e(function(){return chunkKMN5RHLX_cjs.configFieldLabel},"get")}),Object.defineProperty(exports,"redactSecrets",{enumerable:!0,get:e(function(){return chunkKMN5RHLX_cjs.redactSecrets},"get")}),Object.defineProperty(exports,"restoreSecrets",{enumerable:!0,get:e(function(){return chunkKMN5RHLX_cjs.restoreSecrets},"get")}),Object.defineProperty(exports,"summarizeClawConfig",{enumerable:!0,get:e(function(){return chunkKMN5RHLX_cjs.summarizeClawConfig},"get")}),Object.defineProperty(exports,"summarizeConfigDeclaration",{enumerable:!0,get:e(function(){return chunkKMN5RHLX_cjs.summarizeConfigDeclaration},"get")}),Object.defineProperty(exports,"CLAW_MANIFEST_FILENAME",{enumerable:!0,get:e(function(){return chunkROFUQLOZ_cjs.CLAW_MANIFEST_FILENAME},"get")}),Object.defineProperty(exports,"MAX_PLUGIN_MENU_PERMISSION_LENGTH",{enumerable:!0,get:e(function(){return chunkROFUQLOZ_cjs.MAX_PLUGIN_MENU_PERMISSION_LENGTH},"get")}),Object.defineProperty(exports,"PLUGIN_AVATAR_PUBLIC_API_PATH",{enumerable:!0,get:e(function(){return chunkROFUQLOZ_cjs.PLUGIN_AVATAR_PUBLIC_API_PATH},"get")}),Object.defineProperty(exports,"PLUGIN_AVATAR_PUBLIC_PAGES_PATH",{enumerable:!0,get:e(function(){return chunkROFUQLOZ_cjs.PLUGIN_AVATAR_PUBLIC_PAGES_PATH},"get")}),Object.defineProperty(exports,"PLUGIN_BACKEND_PLATFORMS",{enumerable:!0,get:e(function(){return chunkROFUQLOZ_cjs.PLUGIN_BACKEND_PLATFORMS},"get")}),Object.defineProperty(exports,"PLUGIN_BACKEND_RUNTIMES",{enumerable:!0,get:e(function(){return chunkROFUQLOZ_cjs.PLUGIN_BACKEND_RUNTIMES},"get")}),Object.defineProperty(exports,"PLUGIN_MANIFEST_FILENAME",{enumerable:!0,get:e(function(){return chunkROFUQLOZ_cjs.PLUGIN_MANIFEST_FILENAME},"get")}),Object.defineProperty(exports,"PLUGIN_NAV_ICONS",{enumerable:!0,get:e(function(){return chunkROFUQLOZ_cjs.PLUGIN_NAV_ICONS},"get")}),Object.defineProperty(exports,"PLUGIN_NAV_ICON_FALLBACK",{enumerable:!0,get:e(function(){return chunkROFUQLOZ_cjs.PLUGIN_NAV_ICON_FALLBACK},"get")}),Object.defineProperty(exports,"PLUGIN_PART_DEFAULTS",{enumerable:!0,get:e(function(){return chunkROFUQLOZ_cjs.PLUGIN_PART_DEFAULTS},"get")}),Object.defineProperty(exports,"PLUGIN_PART_NAMES",{enumerable:!0,get:e(function(){return chunkROFUQLOZ_cjs.PLUGIN_PART_NAMES},"get")}),Object.defineProperty(exports,"PLUGIN_PUBLIC_API_PATH",{enumerable:!0,get:e(function(){return chunkROFUQLOZ_cjs.PLUGIN_PUBLIC_API_PATH},"get")}),Object.defineProperty(exports,"PLUGIN_PUBLIC_PAGES_PATH",{enumerable:!0,get:e(function(){return chunkROFUQLOZ_cjs.PLUGIN_PUBLIC_PAGES_PATH},"get")}),Object.defineProperty(exports,"PLUGIN_PUBLIC_ROUTE_METHODS",{enumerable:!0,get:e(function(){return chunkROFUQLOZ_cjs.PLUGIN_PUBLIC_ROUTE_METHODS},"get")}),Object.defineProperty(exports,"PLUGIN_SUPPORTED_LOCALES",{enumerable:!0,get:e(function(){return chunkROFUQLOZ_cjs.PLUGIN_SUPPORTED_LOCALES},"get")}),Object.defineProperty(exports,"declaredPartNames",{enumerable:!0,get:e(function(){return chunkROFUQLOZ_cjs.declaredPartNames},"get")}),Object.defineProperty(exports,"formatPublicRoute",{enumerable:!0,get:e(function(){return chunkROFUQLOZ_cjs.formatPublicRoute},"get")}),Object.defineProperty(exports,"localizedTextToString",{enumerable:!0,get:e(function(){return chunkROFUQLOZ_cjs.localizedTextToString},"get")}),Object.defineProperty(exports,"matchPublicRoute",{enumerable:!0,get:e(function(){return chunkROFUQLOZ_cjs.matchPublicRoute},"get")}),Object.defineProperty(exports,"pluginApiPath",{enumerable:!0,get:e(function(){return chunkROFUQLOZ_cjs.pluginApiPath},"get")}),Object.defineProperty(exports,"pluginBasePath",{enumerable:!0,get:e(function(){return chunkROFUQLOZ_cjs.pluginBasePath},"get")}),Object.defineProperty(exports,"pluginI18nKey",{enumerable:!0,get:e(function(){return chunkROFUQLOZ_cjs.pluginI18nKey},"get")}),Object.defineProperty(exports,"pluginI18nNamespace",{enumerable:!0,get:e(function(){return chunkROFUQLOZ_cjs.pluginI18nNamespace},"get")}),Object.defineProperty(exports,"pluginMenuKey",{enumerable:!0,get:e(function(){return chunkROFUQLOZ_cjs.pluginMenuKey},"get")}),Object.defineProperty(exports,"pluginMenuPermission",{enumerable:!0,get:e(function(){return chunkROFUQLOZ_cjs.pluginMenuPermission},"get")}),Object.defineProperty(exports,"pluginNavPath",{enumerable:!0,get:e(function(){return chunkROFUQLOZ_cjs.pluginNavPath},"get")}),Object.defineProperty(exports,"publicApiBaseFromPagePath",{enumerable:!0,get:e(function(){return chunkROFUQLOZ_cjs.publicApiBaseFromPagePath},"get")}),Object.defineProperty(exports,"resolvePluginDeclares",{enumerable:!0,get:e(function(){return chunkROFUQLOZ_cjs.resolvePluginDeclares},"get")}),Object.defineProperty(exports,"resolvePluginParts",{enumerable:!0,get:e(function(){return chunkROFUQLOZ_cjs.resolvePluginParts},"get")}),Object.defineProperty(exports,"resolvePluginScope",{enumerable:!0,get:e(function(){return chunkROFUQLOZ_cjs.resolvePluginScope},"get")}),Object.defineProperty(exports,"HOST_API_VERSION",{enumerable:!0,get:e(function(){return chunkC2OCOPZQ_cjs.HOST_API_VERSION},"get")}),Object.defineProperty(exports,"SHARED_MODULE_IDS",{enumerable:!0,get:e(function(){return chunkC2OCOPZQ_cjs.SHARED_MODULE_IDS},"get")}),Object.defineProperty(exports,"hostApiRangeMinimum",{enumerable:!0,get:e(function(){return chunkC2OCOPZQ_cjs.hostApiRangeMinimum},"get")}),Object.defineProperty(exports,"isValidHostApiRange",{enumerable:!0,get:e(function(){return chunkC2OCOPZQ_cjs.isValidHostApiRange},"get")}),Object.defineProperty(exports,"satisfiesHostApiRange",{enumerable:!0,get:e(function(){return chunkC2OCOPZQ_cjs.satisfiesHostApiRange},"get")}),exports.auditDeclarationGaps=auditDeclarationGaps,exports.buildInstallDisclosure=buildInstallDisclosure,exports.diffInstallDisclosure=diffInstallDisclosure,exports.requiresBackendConfig=requiresBackendConfig;
package/dist/index.d.cts CHANGED
@@ -1,5 +1,5 @@
1
- import { P as PluginPublicRoute, a as PluginBackendRuntime, b as PluginScope, c as PluginPartName, d as PluginDeclares, e as PluginConfigSection, f as PluginConfigSectionSummary, T as TegoPluginManifest, L as LocalizedText, g as PluginNavIcon, h as PluginNavEntry, i as PluginAgentReadinessDeclaration } from './manifest-types-DQARCQJt.cjs';
2
- export { C as CLAW_MANIFEST_FILENAME, E as EMPTY_CONFIG_SECTION_SUMMARY, j as PLUGIN_BACKEND_PLATFORMS, k as PLUGIN_BACKEND_RUNTIMES, l as PLUGIN_CONFIG_SECRET_SENTINEL, m as PLUGIN_CONFIG_SECTIONS, n as PLUGIN_MANIFEST_FILENAME, o as PLUGIN_NAV_ICONS, p as PLUGIN_NAV_ICON_FALLBACK, q as PLUGIN_PART_DEFAULTS, r as PLUGIN_PART_NAMES, s as PluginAgentReadinessItem, t as PluginAgentReadinessResponse, u as PluginAuditDeclarations, v as PluginAuditToolDeclaration, w as PluginBackendLimits, x as PluginBackendPart, y as PluginBackendPlatform, z as PluginClawPart, A as PluginConfigDeclaration, B as PluginConfigFieldSchema, D as PluginConfigFieldType, F as PluginConfigSchema, G as PluginConfigUiHint, H as PluginFrontendPart, I as PluginParts, J as PluginPermissions, K as PluginPublicFrontendPart, M as PluginPublicRouteMethod, N as PluginSchemaRepair, O as PluginWorkDelegationDeclaration, R as ResolvedBackendPart, Q as ResolvedClawPart, S as ResolvedFrontendPart, U as ResolvedPluginParts, V as ResolvedPublicFrontendPart, W as applyConfigDefaults, X as configFieldLabel, Y as declaredPartNames, Z as redactSecrets, _ as resolvePluginDeclares, $ as resolvePluginParts, a0 as resolvePluginScope, a1 as restoreSecrets, a2 as summarizeClawConfig, a3 as summarizeConfigDeclaration } from './manifest-types-DQARCQJt.cjs';
1
+ import { a as PluginPublicRoute, b as PluginBackendRuntime, c as PluginScope, d as PluginPartName, e as PluginDeclares, f as PluginConfigSection, g as PluginConfigSectionSummary, T as TegoPluginManifest, L as LocalizedText, h as PluginNavIcon, P as PluginNavEntry, i as PluginAgentReadinessDeclaration } from './manifest-types-CUTNfJTa.cjs';
2
+ export { C as CLAW_MANIFEST_FILENAME, E as EMPTY_CONFIG_SECTION_SUMMARY, j as PLUGIN_BACKEND_PLATFORMS, k as PLUGIN_BACKEND_RUNTIMES, l as PLUGIN_CONFIG_SECRET_SENTINEL, m as PLUGIN_CONFIG_SECTIONS, n as PLUGIN_MANIFEST_FILENAME, o as PLUGIN_NAV_ICONS, p as PLUGIN_NAV_ICON_FALLBACK, q as PLUGIN_PART_DEFAULTS, r as PLUGIN_PART_NAMES, s as PluginAgentReadinessItem, t as PluginAgentReadinessResponse, u as PluginAuditDeclarations, v as PluginAuditToolDeclaration, w as PluginBackendLimits, x as PluginBackendPart, y as PluginBackendPlatform, z as PluginClawPart, A as PluginConfigDeclaration, B as PluginConfigFieldSchema, D as PluginConfigFieldType, F as PluginConfigSchema, G as PluginConfigUiHint, H as PluginFrontendPart, I as PluginParts, J as PluginPermissions, K as PluginPublicFrontendPart, M as PluginPublicRouteMethod, N as PluginSchemaRepair, O as PluginWorkDelegationDeclaration, R as ResolvedBackendPart, Q as ResolvedClawPart, S as ResolvedFrontendPart, U as ResolvedPluginParts, V as ResolvedPublicFrontendPart, W as applyConfigDefaults, X as configFieldLabel, Y as declaredPartNames, Z as redactSecrets, _ as resolvePluginDeclares, $ as resolvePluginParts, a0 as resolvePluginScope, a1 as restoreSecrets, a2 as summarizeClawConfig, a3 as summarizeConfigDeclaration } from './manifest-types-CUTNfJTa.cjs';
3
3
  import { A as AccessCatalog } from './catalog-CSSbrfEf.cjs';
4
4
  import 'zod';
5
5
 
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { P as PluginPublicRoute, a as PluginBackendRuntime, b as PluginScope, c as PluginPartName, d as PluginDeclares, e as PluginConfigSection, f as PluginConfigSectionSummary, T as TegoPluginManifest, L as LocalizedText, g as PluginNavIcon, h as PluginNavEntry, i as PluginAgentReadinessDeclaration } from './manifest-types-DQARCQJt.js';
2
- export { C as CLAW_MANIFEST_FILENAME, E as EMPTY_CONFIG_SECTION_SUMMARY, j as PLUGIN_BACKEND_PLATFORMS, k as PLUGIN_BACKEND_RUNTIMES, l as PLUGIN_CONFIG_SECRET_SENTINEL, m as PLUGIN_CONFIG_SECTIONS, n as PLUGIN_MANIFEST_FILENAME, o as PLUGIN_NAV_ICONS, p as PLUGIN_NAV_ICON_FALLBACK, q as PLUGIN_PART_DEFAULTS, r as PLUGIN_PART_NAMES, s as PluginAgentReadinessItem, t as PluginAgentReadinessResponse, u as PluginAuditDeclarations, v as PluginAuditToolDeclaration, w as PluginBackendLimits, x as PluginBackendPart, y as PluginBackendPlatform, z as PluginClawPart, A as PluginConfigDeclaration, B as PluginConfigFieldSchema, D as PluginConfigFieldType, F as PluginConfigSchema, G as PluginConfigUiHint, H as PluginFrontendPart, I as PluginParts, J as PluginPermissions, K as PluginPublicFrontendPart, M as PluginPublicRouteMethod, N as PluginSchemaRepair, O as PluginWorkDelegationDeclaration, R as ResolvedBackendPart, Q as ResolvedClawPart, S as ResolvedFrontendPart, U as ResolvedPluginParts, V as ResolvedPublicFrontendPart, W as applyConfigDefaults, X as configFieldLabel, Y as declaredPartNames, Z as redactSecrets, _ as resolvePluginDeclares, $ as resolvePluginParts, a0 as resolvePluginScope, a1 as restoreSecrets, a2 as summarizeClawConfig, a3 as summarizeConfigDeclaration } from './manifest-types-DQARCQJt.js';
1
+ import { a as PluginPublicRoute, b as PluginBackendRuntime, c as PluginScope, d as PluginPartName, e as PluginDeclares, f as PluginConfigSection, g as PluginConfigSectionSummary, T as TegoPluginManifest, L as LocalizedText, h as PluginNavIcon, P as PluginNavEntry, i as PluginAgentReadinessDeclaration } from './manifest-types-CUTNfJTa.js';
2
+ export { C as CLAW_MANIFEST_FILENAME, E as EMPTY_CONFIG_SECTION_SUMMARY, j as PLUGIN_BACKEND_PLATFORMS, k as PLUGIN_BACKEND_RUNTIMES, l as PLUGIN_CONFIG_SECRET_SENTINEL, m as PLUGIN_CONFIG_SECTIONS, n as PLUGIN_MANIFEST_FILENAME, o as PLUGIN_NAV_ICONS, p as PLUGIN_NAV_ICON_FALLBACK, q as PLUGIN_PART_DEFAULTS, r as PLUGIN_PART_NAMES, s as PluginAgentReadinessItem, t as PluginAgentReadinessResponse, u as PluginAuditDeclarations, v as PluginAuditToolDeclaration, w as PluginBackendLimits, x as PluginBackendPart, y as PluginBackendPlatform, z as PluginClawPart, A as PluginConfigDeclaration, B as PluginConfigFieldSchema, D as PluginConfigFieldType, F as PluginConfigSchema, G as PluginConfigUiHint, H as PluginFrontendPart, I as PluginParts, J as PluginPermissions, K as PluginPublicFrontendPart, M as PluginPublicRouteMethod, N as PluginSchemaRepair, O as PluginWorkDelegationDeclaration, R as ResolvedBackendPart, Q as ResolvedClawPart, S as ResolvedFrontendPart, U as ResolvedPluginParts, V as ResolvedPublicFrontendPart, W as applyConfigDefaults, X as configFieldLabel, Y as declaredPartNames, Z as redactSecrets, _ as resolvePluginDeclares, $ as resolvePluginParts, a0 as resolvePluginScope, a1 as restoreSecrets, a2 as summarizeClawConfig, a3 as summarizeConfigDeclaration } from './manifest-types-CUTNfJTa.js';
3
3
  import { A as AccessCatalog } from './catalog-CSSbrfEf.js';
4
4
  import 'zod';
5
5
 
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- var A=Object.defineProperty;var t=(e,n)=>A(e,"name",{value:n,configurable:!0});import{localizedTextToString as N,pluginNavPath as I,pluginMenuPermission as g,resolvePluginParts as v,resolvePluginDeclares as S,declaredPartNames as b,resolvePluginScope as L,formatPublicRoute as h}from"./chunk-BTHXQWHT.js";export{CLAW_MANIFEST_FILENAME,MAX_PLUGIN_MENU_PERMISSION_LENGTH,PLUGIN_AVATAR_PUBLIC_API_PATH,PLUGIN_AVATAR_PUBLIC_PAGES_PATH,PLUGIN_BACKEND_PLATFORMS,PLUGIN_BACKEND_RUNTIMES,PLUGIN_MANIFEST_FILENAME,PLUGIN_NAV_ICONS,PLUGIN_NAV_ICON_FALLBACK,PLUGIN_PART_DEFAULTS,PLUGIN_PART_NAMES,PLUGIN_PUBLIC_API_PATH,PLUGIN_PUBLIC_PAGES_PATH,PLUGIN_PUBLIC_ROUTE_METHODS,PLUGIN_SUPPORTED_LOCALES,declaredPartNames,formatPublicRoute,localizedTextToString,matchPublicRoute,pluginApiPath,pluginBasePath,pluginI18nKey,pluginI18nNamespace,pluginMenuKey,pluginMenuPermission,pluginNavPath,publicApiBaseFromPagePath,resolvePluginDeclares,resolvePluginParts,resolvePluginScope}from"./chunk-BTHXQWHT.js";export{HOST_API_VERSION,SHARED_MODULE_IDS,hostApiRangeMinimum,isValidHostApiRange,satisfiesHostApiRange}from"./chunk-7XHF3YSK.js";var T=["frontend","backend","claw"],d="__OPENCLAW_REDACTED__",a={fieldCount:0,required:[],sensitive:[]};function p(e){if(!e)return a;const n=Object.keys(e.schema.properties),o=e.uiHints??{};return{fieldCount:n.length,required:(e.schema.required??[]).filter(s=>n.includes(s)),sensitive:n.filter(s=>o[s]?.sensitive===!0)}}t(p,"summarizeConfigDeclaration");function P(e){if(!e)return a;const n=e.configSchema;if(typeof n!="object"||n===null)return a;const o=n.properties,s=typeof o=="object"&&o!==null?Object.keys(o):[],r=n.required,u=Array.isArray(r)?r.filter(c=>typeof c=="string"&&s.includes(c)):[],i=e.uiHints,f=typeof i=="object"&&i!==null?i:{},l=s.filter(c=>f[c]?.sensitive===!0);return{fieldCount:s.length,required:u,sensitive:l}}t(P,"summarizeClawConfig");function E(e,n){const o={...e};for(const s of n)o[s]===void 0||o[s]===null||(o[s]=d);return o}t(E,"redactSecrets");function m(e,n,o){const s={...e};for(const r of o){if(s[r]!==d)continue;const u=n[r];if(u===void 0){delete s[r];continue}s[r]=u}return s}t(m,"restoreSecrets");function k(e,n){const o={...n};for(const[s,r]of Object.entries(e.properties??{}))o[s]===void 0&&r.default!==void 0&&(o[s]=r.default);return o}t(k,"applyConfigDefaults");function R(e,n,o,s){return n?.label?N(n.label,s):o?.title?o.title:e}t(R,"configFieldLabel");function U(e){if(!e)return[];const n=e.contracts;if(typeof n!="object"||n===null)return[];const o=n.tools;return Array.isArray(o)?o.filter(s=>typeof s=="string"):[]}t(U,"readClawTools");function _(e,n){const o=Object.keys(e.audit?.tools??{}),s=new Set(n);return{undeclared:n.filter(r=>!e.audit?.tools?.[r]),unknown:o.filter(r=>!s.has(r))}}t(_,"auditDeclarationGaps");function C(e,n=null,o=null){const s=(e.parts.frontend?.nav??[]).map(i=>({key:i.key,labelKey:i.labelKey,permission:g(e.id,i.key),path:I(e.id,i.path)})),r=v(e).backend,u=U(n);return{requiredPermissions:[...new Set(e.permissions?.required??[])].sort(),egress:r?.egress??[],publicRoutes:(r?.publicRoutes??[]).map(h).sort(),...r?{backendRuntime:r.runtime}:{},scope:L(e),parts:b(e),declares:S(e),nav:s,clawTools:u,auditUndeclaredTools:_(e,u).undeclared,config:{frontend:p(e.parts.frontend?.config),backend:p(e.parts.backend?.config),claw:P(n)},...o?{access:{permissions:Object.values(o.permissions).filter(i=>!i.reserved).length,roles:Object.keys(o.roles).length}}:{}}}t(C,"buildInstallDisclosure");function y(e){return e.config.backend.required.length>0}t(y,"requiresBackendConfig");function G(e,n){const o=[];for(const i of n.requiredPermissions??[])e?.requiredPermissions?.includes(i)||o.push({kind:"permission",value:i});for(const i of n.egress??[])!e?.egress?.includes(i)&&!e?.egress?.includes("*")&&o.push({kind:"egress",value:i});for(const i of n.publicRoutes??[])e?.publicRoutes?.includes(i)||o.push({kind:"publicRoute",value:i});const s=new Set(e?.parts??[]);for(const i of n.parts)s.has(i)||o.push({kind:"part",value:i});for(const i of["database","storage","events"])n.declares[i]&&(e?.declares[i]||o.push({kind:"declares",value:i}));const r=new Set((e?.nav??[]).map(i=>i.key));for(const i of n.nav)r.has(i.key)||o.push({kind:"nav",value:i.key});const u=new Set(e?.clawTools??[]);for(const i of n.clawTools)u.has(i)||o.push({kind:"clawTool",value:i});for(const i of["frontend","backend","claw"]){const f=new Set(e?.config[i]?.required??[]);for(const l of n.config[i].required)f.has(l)||o.push({kind:"configRequired",value:`${i}.${l}`})}return o}t(G,"diffInstallDisclosure");export{a as EMPTY_CONFIG_SECTION_SUMMARY,d as PLUGIN_CONFIG_SECRET_SENTINEL,T as PLUGIN_CONFIG_SECTIONS,k as applyConfigDefaults,_ as auditDeclarationGaps,C as buildInstallDisclosure,R as configFieldLabel,G as diffInstallDisclosure,E as redactSecrets,y as requiresBackendConfig,m as restoreSecrets,P as summarizeClawConfig,p as summarizeConfigDeclaration};
1
+ var d=Object.defineProperty;var l=(o,s)=>d(o,"name",{value:s,configurable:!0});import{summarizeClawConfig as f,summarizeConfigDeclaration as a}from"./chunk-2ORO36BY.js";export{EMPTY_CONFIG_SECTION_SUMMARY,PLUGIN_CONFIG_SECRET_SENTINEL,PLUGIN_CONFIG_SECTIONS,applyConfigDefaults,configFieldLabel,redactSecrets,restoreSecrets,summarizeClawConfig,summarizeConfigDeclaration}from"./chunk-2ORO36BY.js";import{pluginNavPath as p,pluginMenuPermission as _,resolvePluginParts as I,resolvePluginDeclares as N,declaredPartNames as A,resolvePluginScope as g,formatPublicRoute as S}from"./chunk-BTHXQWHT.js";export{CLAW_MANIFEST_FILENAME,MAX_PLUGIN_MENU_PERMISSION_LENGTH,PLUGIN_AVATAR_PUBLIC_API_PATH,PLUGIN_AVATAR_PUBLIC_PAGES_PATH,PLUGIN_BACKEND_PLATFORMS,PLUGIN_BACKEND_RUNTIMES,PLUGIN_MANIFEST_FILENAME,PLUGIN_NAV_ICONS,PLUGIN_NAV_ICON_FALLBACK,PLUGIN_PART_DEFAULTS,PLUGIN_PART_NAMES,PLUGIN_PUBLIC_API_PATH,PLUGIN_PUBLIC_PAGES_PATH,PLUGIN_PUBLIC_ROUTE_METHODS,PLUGIN_SUPPORTED_LOCALES,declaredPartNames,formatPublicRoute,localizedTextToString,matchPublicRoute,pluginApiPath,pluginBasePath,pluginI18nKey,pluginI18nNamespace,pluginMenuKey,pluginMenuPermission,pluginNavPath,publicApiBaseFromPagePath,resolvePluginDeclares,resolvePluginParts,resolvePluginScope}from"./chunk-BTHXQWHT.js";export{HOST_API_VERSION,SHARED_MODULE_IDS,hostApiRangeMinimum,isValidHostApiRange,satisfiesHostApiRange}from"./chunk-7XHF3YSK.js";function L(o){if(!o)return[];const s=o.contracts;if(typeof s!="object"||s===null)return[];const n=s.tools;return Array.isArray(n)?n.filter(i=>typeof i=="string"):[]}l(L,"readClawTools");function c(o,s){const n=Object.keys(o.audit?.tools??{}),i=new Set(s);return{undeclared:s.filter(r=>!o.audit?.tools?.[r]),unknown:n.filter(r=>!i.has(r))}}l(c,"auditDeclarationGaps");function T(o,s=null,n=null){const i=(o.parts.frontend?.nav??[]).map(e=>({key:e.key,labelKey:e.labelKey,permission:_(o.id,e.key),path:p(o.id,e.path)})),r=I(o).backend,t=L(s);return{requiredPermissions:[...new Set(o.permissions?.required??[])].sort(),egress:r?.egress??[],publicRoutes:(r?.publicRoutes??[]).map(S).sort(),...r?{backendRuntime:r.runtime}:{},scope:g(o),parts:A(o),declares:N(o),nav:i,clawTools:t,auditUndeclaredTools:c(o,t).undeclared,config:{frontend:a(o.parts.frontend?.config),backend:a(o.parts.backend?.config),claw:f(s)},...n?{access:{permissions:Object.values(n.permissions).filter(e=>!e.reserved).length,roles:Object.keys(n.roles).length}}:{}}}l(T,"buildInstallDisclosure");function E(o){return o.config.backend.required.length>0}l(E,"requiresBackendConfig");function m(o,s){const n=[];for(const e of s.requiredPermissions??[])o?.requiredPermissions?.includes(e)||n.push({kind:"permission",value:e});for(const e of s.egress??[])!o?.egress?.includes(e)&&!o?.egress?.includes("*")&&n.push({kind:"egress",value:e});for(const e of s.publicRoutes??[])o?.publicRoutes?.includes(e)||n.push({kind:"publicRoute",value:e});const i=new Set(o?.parts??[]);for(const e of s.parts)i.has(e)||n.push({kind:"part",value:e});for(const e of["database","storage","events"])s.declares[e]&&(o?.declares[e]||n.push({kind:"declares",value:e}));const r=new Set((o?.nav??[]).map(e=>e.key));for(const e of s.nav)r.has(e.key)||n.push({kind:"nav",value:e.key});const t=new Set(o?.clawTools??[]);for(const e of s.clawTools)t.has(e)||n.push({kind:"clawTool",value:e});for(const e of["frontend","backend","claw"]){const P=new Set(o?.config[e]?.required??[]);for(const u of s.config[e].required)P.has(u)||n.push({kind:"configRequired",value:`${e}.${u}`})}return n}l(m,"diffInstallDisclosure");export{c as auditDeclarationGaps,T as buildInstallDisclosure,m as diffInstallDisclosure,E as requiresBackendConfig};