@zhama/tego-plugin-sdk 1.36.1 → 1.37.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +50 -3
- package/agent/RULES.md +123 -0
- package/agent/guides/access.md +39 -0
- package/agent/guides/backend.md +76 -0
- package/agent/guides/claw.md +18 -0
- package/agent/guides/desktop-web.md +48 -0
- package/agent/guides/frontend.md +83 -0
- package/agent/guides/host-api-versions.md +34 -0
- package/agent/guides/i18n.md +17 -0
- package/agent/guides/manifest.md +26 -0
- package/agent/guides/migrations.md +17 -0
- package/agent/guides/storage.md +18 -0
- package/agent/guides/testing.md +17 -0
- package/agent/guides/ui.md +22 -0
- package/agent/reference/plugin-sdk-api.md +561 -0
- package/bin/tego-plugin-pack.mjs +1 -1
- package/bin/tego-plugin.mjs +4 -2
- package/dist/chunk-2NTAWYCG.js +1 -0
- package/dist/chunk-2P6UEAPV.cjs +1 -0
- package/dist/chunk-45Y4CR4R.cjs +1 -0
- package/dist/{chunk-THMWRUAT.cjs → chunk-4LKRXDYY.cjs} +13 -12
- package/dist/{chunk-7XHF3YSK.js → chunk-56QOZQTY.js} +1 -1
- package/dist/{chunk-C2OCOPZQ.cjs → chunk-6HNG5OZI.cjs} +1 -1
- package/dist/chunk-DEGQDJF6.js +1 -0
- package/dist/chunk-EIVA5BR6.js +1 -0
- package/dist/chunk-FCYAAOHC.js +20 -0
- package/dist/chunk-HZ4YWRYX.cjs +5 -0
- package/dist/chunk-I5Z3ECC4.js +5 -0
- package/dist/chunk-INCA3GFW.js +1 -0
- package/dist/chunk-IVJECPGG.js +1 -0
- package/dist/chunk-MWMGJJ74.cjs +1 -0
- package/dist/chunk-N4SXZZPY.cjs +1 -0
- package/dist/chunk-SKNPNPJP.cjs +1 -0
- package/dist/dev.cjs +358 -0
- package/dist/dev.d.cts +144 -0
- package/dist/dev.d.ts +144 -0
- package/dist/dev.js +358 -0
- package/dist/doctor.cjs +8 -0
- package/dist/doctor.d.cts +62 -0
- package/dist/doctor.d.ts +62 -0
- package/dist/doctor.js +8 -0
- package/dist/frontend.d.cts +33 -1
- package/dist/frontend.d.ts +33 -1
- package/dist/hono.cjs +1 -0
- package/dist/hono.d.cts +84 -0
- package/dist/hono.d.ts +84 -0
- package/dist/hono.js +1 -0
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +8 -3
- package/dist/index.d.ts +8 -3
- package/dist/index.js +1 -1
- package/dist/{manifest-types-DQARCQJt.d.cts → manifest-types-CUTNfJTa.d.cts} +1 -1
- package/dist/{manifest-types-DQARCQJt.d.ts → manifest-types-CUTNfJTa.d.ts} +1 -1
- package/dist/manifest.cjs +1 -1
- package/dist/manifest.d.cts +55 -2
- package/dist/manifest.d.ts +55 -2
- package/dist/manifest.js +1 -1
- package/dist/migrations-sync.cjs +1 -0
- package/dist/migrations-sync.d.cts +20 -0
- package/dist/migrations-sync.d.ts +20 -0
- package/dist/migrations-sync.js +1 -0
- package/dist/pack.cjs +1 -1
- package/dist/pack.d.cts +8 -2
- package/dist/pack.d.ts +8 -2
- package/dist/pack.js +1 -1
- package/dist/publish.cjs +1 -1
- package/dist/publish.d.cts +1 -1
- package/dist/publish.d.ts +1 -1
- package/dist/publish.js +1 -1
- package/dist/react.cjs +1 -0
- package/dist/react.d.cts +101 -0
- package/dist/react.d.ts +101 -0
- package/dist/react.js +1 -0
- package/dist/scaffold.cjs +672 -17
- package/dist/scaffold.d.cts +42 -18
- package/dist/scaffold.d.ts +42 -18
- package/dist/scaffold.js +674 -19
- package/dist/server-runtime.cjs +1 -1
- package/dist/server-runtime.d.cts +27 -2
- package/dist/server-runtime.d.ts +27 -2
- package/dist/server-runtime.js +1 -1
- package/dist/testing.cjs +6 -2
- package/dist/testing.d.cts +19 -1
- package/dist/testing.d.ts +19 -1
- package/dist/testing.js +6 -2
- package/dist/verify-FF2RD2MV.cjs +1 -0
- package/dist/verify-W7ZTUCO4.js +1 -0
- package/dist/vite.cjs +1 -1
- package/dist/vite.d.cts +27 -1
- package/dist/vite.d.ts +27 -1
- package/dist/vite.js +1 -1
- package/package.json +37 -3
- package/dist/chunk-3KUOBGJN.js +0 -19
- package/dist/chunk-3WA3M347.cjs +0 -1
- package/dist/chunk-5CU33JVY.js +0 -1
- package/dist/chunk-7K37PVGV.js +0 -5
- package/dist/chunk-BTHXQWHT.js +0 -1
- package/dist/chunk-ROFUQLOZ.cjs +0 -1
- package/dist/chunk-W7C357A6.cjs +0 -5
|
@@ -624,4 +624,4 @@ interface ResolvedPluginParts {
|
|
|
624
624
|
*/
|
|
625
625
|
declare function resolvePluginParts(manifest: TegoPluginManifest): ResolvedPluginParts;
|
|
626
626
|
|
|
627
|
-
export { resolvePluginParts as $, type PluginConfigDeclaration as A, type PluginConfigFieldSchema as B, CLAW_MANIFEST_FILENAME as C, type PluginConfigFieldType as D, EMPTY_CONFIG_SECTION_SUMMARY as E, type PluginConfigSchema as F, type PluginConfigUiHint as G, type PluginFrontendPart as H, type PluginParts as I, type PluginPermissions as J, type PluginPublicFrontendPart as K, type LocalizedText as L, type PluginPublicRouteMethod as M, type PluginSchemaRepair as N, type PluginWorkDelegationDeclaration as O, type
|
|
627
|
+
export { resolvePluginParts as $, type PluginConfigDeclaration as A, type PluginConfigFieldSchema as B, CLAW_MANIFEST_FILENAME as C, type PluginConfigFieldType as D, EMPTY_CONFIG_SECTION_SUMMARY as E, type PluginConfigSchema as F, type PluginConfigUiHint as G, type PluginFrontendPart as H, type PluginParts as I, type PluginPermissions as J, type PluginPublicFrontendPart as K, type LocalizedText as L, type PluginPublicRouteMethod as M, type PluginSchemaRepair as N, type PluginWorkDelegationDeclaration as O, type PluginNavEntry as P, type ResolvedClawPart as Q, type ResolvedBackendPart as R, type ResolvedFrontendPart as S, type TegoPluginManifest as T, type ResolvedPluginParts as U, type ResolvedPublicFrontendPart as V, applyConfigDefaults as W, configFieldLabel as X, declaredPartNames as Y, redactSecrets as Z, resolvePluginDeclares as _, type PluginPublicRoute as a, resolvePluginScope as a0, restoreSecrets as a1, summarizeClawConfig as a2, summarizeConfigDeclaration as a3, type PluginBackendRuntime as b, type PluginScope as c, type PluginPartName as d, type PluginDeclares as e, type PluginConfigSection as f, type PluginConfigSectionSummary as g, type PluginNavIcon as h, type PluginAgentReadinessDeclaration as i, PLUGIN_BACKEND_PLATFORMS as j, PLUGIN_BACKEND_RUNTIMES as k, PLUGIN_CONFIG_SECRET_SENTINEL as l, PLUGIN_CONFIG_SECTIONS as m, PLUGIN_MANIFEST_FILENAME as n, PLUGIN_NAV_ICONS as o, PLUGIN_NAV_ICON_FALLBACK as p, PLUGIN_PART_DEFAULTS as q, PLUGIN_PART_NAMES as r, type PluginAgentReadinessItem as s, type PluginAgentReadinessResponse as t, type PluginAuditDeclarations as u, type PluginAuditToolDeclaration as v, type PluginBackendLimits as w, type PluginBackendPart as x, type PluginBackendPlatform as y, type PluginClawPart as z };
|
|
@@ -624,4 +624,4 @@ interface ResolvedPluginParts {
|
|
|
624
624
|
*/
|
|
625
625
|
declare function resolvePluginParts(manifest: TegoPluginManifest): ResolvedPluginParts;
|
|
626
626
|
|
|
627
|
-
export { resolvePluginParts as $, type PluginConfigDeclaration as A, type PluginConfigFieldSchema as B, CLAW_MANIFEST_FILENAME as C, type PluginConfigFieldType as D, EMPTY_CONFIG_SECTION_SUMMARY as E, type PluginConfigSchema as F, type PluginConfigUiHint as G, type PluginFrontendPart as H, type PluginParts as I, type PluginPermissions as J, type PluginPublicFrontendPart as K, type LocalizedText as L, type PluginPublicRouteMethod as M, type PluginSchemaRepair as N, type PluginWorkDelegationDeclaration as O, type
|
|
627
|
+
export { resolvePluginParts as $, type PluginConfigDeclaration as A, type PluginConfigFieldSchema as B, CLAW_MANIFEST_FILENAME as C, type PluginConfigFieldType as D, EMPTY_CONFIG_SECTION_SUMMARY as E, type PluginConfigSchema as F, type PluginConfigUiHint as G, type PluginFrontendPart as H, type PluginParts as I, type PluginPermissions as J, type PluginPublicFrontendPart as K, type LocalizedText as L, type PluginPublicRouteMethod as M, type PluginSchemaRepair as N, type PluginWorkDelegationDeclaration as O, type PluginNavEntry as P, type ResolvedClawPart as Q, type ResolvedBackendPart as R, type ResolvedFrontendPart as S, type TegoPluginManifest as T, type ResolvedPluginParts as U, type ResolvedPublicFrontendPart as V, applyConfigDefaults as W, configFieldLabel as X, declaredPartNames as Y, redactSecrets as Z, resolvePluginDeclares as _, type PluginPublicRoute as a, resolvePluginScope as a0, restoreSecrets as a1, summarizeClawConfig as a2, summarizeConfigDeclaration as a3, type PluginBackendRuntime as b, type PluginScope as c, type PluginPartName as d, type PluginDeclares as e, type PluginConfigSection as f, type PluginConfigSectionSummary as g, type PluginNavIcon as h, type PluginAgentReadinessDeclaration as i, PLUGIN_BACKEND_PLATFORMS as j, PLUGIN_BACKEND_RUNTIMES as k, PLUGIN_CONFIG_SECRET_SENTINEL as l, PLUGIN_CONFIG_SECTIONS as m, PLUGIN_MANIFEST_FILENAME as n, PLUGIN_NAV_ICONS as o, PLUGIN_NAV_ICON_FALLBACK as p, PLUGIN_PART_DEFAULTS as q, PLUGIN_PART_NAMES as r, type PluginAgentReadinessItem as s, type PluginAgentReadinessResponse as t, type PluginAuditDeclarations as u, type PluginAuditToolDeclaration as v, type PluginBackendLimits as w, type PluginBackendPart as x, type PluginBackendPlatform as y, type PluginClawPart as z };
|
package/dist/manifest.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var n=Object.defineProperty;var e=(r,t)=>n(r,"name",{value:t,configurable:!0});var
|
|
1
|
+
"use strict";var n=Object.defineProperty;var e=(r,t)=>n(r,"name",{value:t,configurable:!0});var chunkSKNPNPJP_cjs=require("./chunk-SKNPNPJP.cjs"),chunk45Y4CR4R_cjs=require("./chunk-45Y4CR4R.cjs");require("./chunk-2P6UEAPV.cjs"),require("./chunk-N4SXZZPY.cjs"),require("./chunk-6HNG5OZI.cjs"),require("./chunk-AJY7ZHXK.cjs"),require("./chunk-OP64Y4IN.cjs"),Object.defineProperty(exports,"PYTHON_LOCK_FILENAME",{enumerable:!0,get:e(function(){return chunkSKNPNPJP_cjs.PYTHON_LOCK_FILENAME},"get")}),Object.defineProperty(exports,"PYTHON_RUNNER_VERSION",{enumerable:!0,get:e(function(){return chunkSKNPNPJP_cjs.PYTHON_RUNNER_VERSION},"get")}),Object.defineProperty(exports,"PYTHON_WHEELS_DIR",{enumerable:!0,get:e(function(){return chunkSKNPNPJP_cjs.PYTHON_WHEELS_DIR},"get")}),Object.defineProperty(exports,"checkPluginAccessCatalog",{enumerable:!0,get:e(function(){return chunkSKNPNPJP_cjs.checkPluginAccessCatalog},"get")}),Object.defineProperty(exports,"checkPythonVendoring",{enumerable:!0,get:e(function(){return chunkSKNPNPJP_cjs.checkPythonVendoring},"get")}),Object.defineProperty(exports,"normalizePackageName",{enumerable:!0,get:e(function(){return chunkSKNPNPJP_cjs.normalizePackageName},"get")}),Object.defineProperty(exports,"parseRequirementsLock",{enumerable:!0,get:e(function(){return chunkSKNPNPJP_cjs.parseRequirementsLock},"get")}),Object.defineProperty(exports,"parseTegoPluginManifest",{enumerable:!0,get:e(function(){return chunkSKNPNPJP_cjs.parseTegoPluginManifest},"get")}),Object.defineProperty(exports,"parseWheelFilename",{enumerable:!0,get:e(function(){return chunkSKNPNPJP_cjs.parseWheelFilename},"get")}),Object.defineProperty(exports,"tegoPluginManifestSchema",{enumerable:!0,get:e(function(){return chunkSKNPNPJP_cjs.tegoPluginManifestSchema},"get")}),Object.defineProperty(exports,"LOCALE_FILENAME_PATTERN",{enumerable:!0,get:e(function(){return chunk45Y4CR4R_cjs.LOCALE_FILENAME_PATTERN},"get")}),Object.defineProperty(exports,"MIGRATION_FILENAME_PATTERN",{enumerable:!0,get:e(function(){return chunk45Y4CR4R_cjs.MIGRATION_FILENAME_PATTERN},"get")}),Object.defineProperty(exports,"flattenLocaleKeys",{enumerable:!0,get:e(function(){return chunk45Y4CR4R_cjs.flattenLocaleKeys},"get")}),Object.defineProperty(exports,"verifyFrontendLocales",{enumerable:!0,get:e(function(){return chunk45Y4CR4R_cjs.verifyFrontendLocales},"get")}),Object.defineProperty(exports,"verifyMigrationNames",{enumerable:!0,get:e(function(){return chunk45Y4CR4R_cjs.verifyMigrationNames},"get")});
|
package/dist/manifest.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import { T as TegoPluginManifest, y as PluginBackendPlatform } from './manifest-types-
|
|
2
|
+
import { T as TegoPluginManifest, P as PluginNavEntry, y as PluginBackendPlatform } from './manifest-types-CUTNfJTa.cjs';
|
|
3
3
|
import { A as AccessCatalog } from './catalog-CSSbrfEf.cjs';
|
|
4
4
|
|
|
5
5
|
/**
|
|
@@ -22,6 +22,59 @@ type PluginAccessCatalogResult = {
|
|
|
22
22
|
*/
|
|
23
23
|
declare function checkPluginAccessCatalog(manifest: Pick<TegoPluginManifest, 'access' | 'parts'>, raw: unknown): PluginAccessCatalogResult;
|
|
24
24
|
|
|
25
|
+
/** `zh-CN.json`, `en.json` — the locale file shape the host's loader expects. */
|
|
26
|
+
declare const LOCALE_FILENAME_PATTERN: RegExp;
|
|
27
|
+
/**
|
|
28
|
+
* `0001_initial.sql`. The numeric prefix is what makes the apply order
|
|
29
|
+
* deterministic; without it two migrations could be applied in either order,
|
|
30
|
+
* which is only discovered when a column is missing in production.
|
|
31
|
+
*/
|
|
32
|
+
declare const MIGRATION_FILENAME_PATTERN: RegExp;
|
|
33
|
+
/** Read access to a plugin package or source tree, paths relative to its root with `/`. */
|
|
34
|
+
interface PluginTreeReader {
|
|
35
|
+
/** Names of the files directly in `dir` (not nested deeper); empty when it does not exist. */
|
|
36
|
+
list(dir: string): Promise<string[]>;
|
|
37
|
+
/** The file as UTF-8, or `null` when absent. */
|
|
38
|
+
readText(path: string): Promise<string | null>;
|
|
39
|
+
}
|
|
40
|
+
/** Every leaf path of a nested translation object, in `a.b.c` form. */
|
|
41
|
+
declare function flattenLocaleKeys(value: unknown, prefix?: string, into?: Set<string>): Set<string>;
|
|
42
|
+
interface LocaleVerification {
|
|
43
|
+
/** Locale tags found (`zh-CN`, `en`, …), in directory order. */
|
|
44
|
+
locales: string[];
|
|
45
|
+
/** Parsed bundles by tag, for checks that need the values. */
|
|
46
|
+
bundles: Map<string, unknown>;
|
|
47
|
+
errors: string[];
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Every locale bundle exists, parses, and carries the same keys.
|
|
51
|
+
*
|
|
52
|
+
* Three separate failures, all of which used to reach a user as a sidebar row
|
|
53
|
+
* showing `crm.nav.deals`:
|
|
54
|
+
*
|
|
55
|
+
* - a missing language, where the platform is translated and this plugin is
|
|
56
|
+
* not. Falling back would hide it permanently, so it is refused where the
|
|
57
|
+
* author can act
|
|
58
|
+
* - a key present in one bundle and absent in another, which is what a
|
|
59
|
+
* half-finished translation pass leaves behind
|
|
60
|
+
* - a nav entry pointing at a key nobody wrote
|
|
61
|
+
*
|
|
62
|
+
* Keys are compared against `zh-CN`, the platform's own default, rather than
|
|
63
|
+
* against a union of all files — a union would let a typo in one file demand
|
|
64
|
+
* the same typo in the other nine.
|
|
65
|
+
*/
|
|
66
|
+
declare function verifyFrontendLocales(reader: PluginTreeReader, frontend: {
|
|
67
|
+
i18nDirPath: string;
|
|
68
|
+
nav: PluginNavEntry[];
|
|
69
|
+
}): Promise<LocaleVerification>;
|
|
70
|
+
interface MigrationVerification {
|
|
71
|
+
/** Valid migration file names, sorted (= apply order). */
|
|
72
|
+
migrations: string[];
|
|
73
|
+
errors: string[];
|
|
74
|
+
}
|
|
75
|
+
/** Migration files are `<ordinal>_<description>.sql` with unique ordinals. */
|
|
76
|
+
declare function verifyMigrationNames(reader: PluginTreeReader, migrationsDirPath: string): Promise<MigrationVerification>;
|
|
77
|
+
|
|
25
78
|
/**
|
|
26
79
|
* Whether a python backend's vendored wheels will install in the runner.
|
|
27
80
|
*
|
|
@@ -2821,4 +2874,4 @@ interface PluginManifestParseResult {
|
|
|
2821
2874
|
*/
|
|
2822
2875
|
declare function parseTegoPluginManifest(value: unknown): PluginManifestParseResult;
|
|
2823
2876
|
|
|
2824
|
-
export { type LockedRequirement, PYTHON_LOCK_FILENAME, PYTHON_RUNNER_VERSION, PYTHON_WHEELS_DIR, type ParsedTegoPluginManifest, type ParsedWheelFilename, type PluginAccessCatalogResult, type PluginManifestParseResult, type VendoredWheel, checkPluginAccessCatalog, checkPythonVendoring, normalizePackageName, parseRequirementsLock, parseTegoPluginManifest, parseWheelFilename, tegoPluginManifestSchema };
|
|
2877
|
+
export { LOCALE_FILENAME_PATTERN, type LocaleVerification, type LockedRequirement, MIGRATION_FILENAME_PATTERN, type MigrationVerification, PYTHON_LOCK_FILENAME, PYTHON_RUNNER_VERSION, PYTHON_WHEELS_DIR, type ParsedTegoPluginManifest, type ParsedWheelFilename, type PluginAccessCatalogResult, type PluginManifestParseResult, type PluginTreeReader, type VendoredWheel, checkPluginAccessCatalog, checkPythonVendoring, flattenLocaleKeys, normalizePackageName, parseRequirementsLock, parseTegoPluginManifest, parseWheelFilename, tegoPluginManifestSchema, verifyFrontendLocales, verifyMigrationNames };
|
package/dist/manifest.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import { T as TegoPluginManifest, y as PluginBackendPlatform } from './manifest-types-
|
|
2
|
+
import { T as TegoPluginManifest, P as PluginNavEntry, y as PluginBackendPlatform } from './manifest-types-CUTNfJTa.js';
|
|
3
3
|
import { A as AccessCatalog } from './catalog-CSSbrfEf.js';
|
|
4
4
|
|
|
5
5
|
/**
|
|
@@ -22,6 +22,59 @@ type PluginAccessCatalogResult = {
|
|
|
22
22
|
*/
|
|
23
23
|
declare function checkPluginAccessCatalog(manifest: Pick<TegoPluginManifest, 'access' | 'parts'>, raw: unknown): PluginAccessCatalogResult;
|
|
24
24
|
|
|
25
|
+
/** `zh-CN.json`, `en.json` — the locale file shape the host's loader expects. */
|
|
26
|
+
declare const LOCALE_FILENAME_PATTERN: RegExp;
|
|
27
|
+
/**
|
|
28
|
+
* `0001_initial.sql`. The numeric prefix is what makes the apply order
|
|
29
|
+
* deterministic; without it two migrations could be applied in either order,
|
|
30
|
+
* which is only discovered when a column is missing in production.
|
|
31
|
+
*/
|
|
32
|
+
declare const MIGRATION_FILENAME_PATTERN: RegExp;
|
|
33
|
+
/** Read access to a plugin package or source tree, paths relative to its root with `/`. */
|
|
34
|
+
interface PluginTreeReader {
|
|
35
|
+
/** Names of the files directly in `dir` (not nested deeper); empty when it does not exist. */
|
|
36
|
+
list(dir: string): Promise<string[]>;
|
|
37
|
+
/** The file as UTF-8, or `null` when absent. */
|
|
38
|
+
readText(path: string): Promise<string | null>;
|
|
39
|
+
}
|
|
40
|
+
/** Every leaf path of a nested translation object, in `a.b.c` form. */
|
|
41
|
+
declare function flattenLocaleKeys(value: unknown, prefix?: string, into?: Set<string>): Set<string>;
|
|
42
|
+
interface LocaleVerification {
|
|
43
|
+
/** Locale tags found (`zh-CN`, `en`, …), in directory order. */
|
|
44
|
+
locales: string[];
|
|
45
|
+
/** Parsed bundles by tag, for checks that need the values. */
|
|
46
|
+
bundles: Map<string, unknown>;
|
|
47
|
+
errors: string[];
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Every locale bundle exists, parses, and carries the same keys.
|
|
51
|
+
*
|
|
52
|
+
* Three separate failures, all of which used to reach a user as a sidebar row
|
|
53
|
+
* showing `crm.nav.deals`:
|
|
54
|
+
*
|
|
55
|
+
* - a missing language, where the platform is translated and this plugin is
|
|
56
|
+
* not. Falling back would hide it permanently, so it is refused where the
|
|
57
|
+
* author can act
|
|
58
|
+
* - a key present in one bundle and absent in another, which is what a
|
|
59
|
+
* half-finished translation pass leaves behind
|
|
60
|
+
* - a nav entry pointing at a key nobody wrote
|
|
61
|
+
*
|
|
62
|
+
* Keys are compared against `zh-CN`, the platform's own default, rather than
|
|
63
|
+
* against a union of all files — a union would let a typo in one file demand
|
|
64
|
+
* the same typo in the other nine.
|
|
65
|
+
*/
|
|
66
|
+
declare function verifyFrontendLocales(reader: PluginTreeReader, frontend: {
|
|
67
|
+
i18nDirPath: string;
|
|
68
|
+
nav: PluginNavEntry[];
|
|
69
|
+
}): Promise<LocaleVerification>;
|
|
70
|
+
interface MigrationVerification {
|
|
71
|
+
/** Valid migration file names, sorted (= apply order). */
|
|
72
|
+
migrations: string[];
|
|
73
|
+
errors: string[];
|
|
74
|
+
}
|
|
75
|
+
/** Migration files are `<ordinal>_<description>.sql` with unique ordinals. */
|
|
76
|
+
declare function verifyMigrationNames(reader: PluginTreeReader, migrationsDirPath: string): Promise<MigrationVerification>;
|
|
77
|
+
|
|
25
78
|
/**
|
|
26
79
|
* Whether a python backend's vendored wheels will install in the runner.
|
|
27
80
|
*
|
|
@@ -2821,4 +2874,4 @@ interface PluginManifestParseResult {
|
|
|
2821
2874
|
*/
|
|
2822
2875
|
declare function parseTegoPluginManifest(value: unknown): PluginManifestParseResult;
|
|
2823
2876
|
|
|
2824
|
-
export { type LockedRequirement, PYTHON_LOCK_FILENAME, PYTHON_RUNNER_VERSION, PYTHON_WHEELS_DIR, type ParsedTegoPluginManifest, type ParsedWheelFilename, type PluginAccessCatalogResult, type PluginManifestParseResult, type VendoredWheel, checkPluginAccessCatalog, checkPythonVendoring, normalizePackageName, parseRequirementsLock, parseTegoPluginManifest, parseWheelFilename, tegoPluginManifestSchema };
|
|
2877
|
+
export { LOCALE_FILENAME_PATTERN, type LocaleVerification, type LockedRequirement, MIGRATION_FILENAME_PATTERN, type MigrationVerification, PYTHON_LOCK_FILENAME, PYTHON_RUNNER_VERSION, PYTHON_WHEELS_DIR, type ParsedTegoPluginManifest, type ParsedWheelFilename, type PluginAccessCatalogResult, type PluginManifestParseResult, type PluginTreeReader, type VendoredWheel, checkPluginAccessCatalog, checkPythonVendoring, flattenLocaleKeys, normalizePackageName, parseRequirementsLock, parseTegoPluginManifest, parseWheelFilename, tegoPluginManifestSchema, verifyFrontendLocales, verifyMigrationNames };
|
package/dist/manifest.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export{PYTHON_LOCK_FILENAME,PYTHON_RUNNER_VERSION,PYTHON_WHEELS_DIR,checkPluginAccessCatalog,checkPythonVendoring,normalizePackageName,parseRequirementsLock,parseTegoPluginManifest,parseWheelFilename,tegoPluginManifestSchema}from"./chunk-
|
|
1
|
+
export{PYTHON_LOCK_FILENAME,PYTHON_RUNNER_VERSION,PYTHON_WHEELS_DIR,checkPluginAccessCatalog,checkPythonVendoring,normalizePackageName,parseRequirementsLock,parseTegoPluginManifest,parseWheelFilename,tegoPluginManifestSchema}from"./chunk-EIVA5BR6.js";export{LOCALE_FILENAME_PATTERN,MIGRATION_FILENAME_PATTERN,flattenLocaleKeys,verifyFrontendLocales,verifyMigrationNames}from"./chunk-2NTAWYCG.js";import"./chunk-IVJECPGG.js";import"./chunk-INCA3GFW.js";import"./chunk-56QOZQTY.js";import"./chunk-VMCGDDGP.js";import"./chunk-SNUCO2MK.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";var f=Object.defineProperty;var o=(e,t)=>f(e,"name",{value:t,configurable:!0});var promises=require("fs/promises"),path=require("path");function parseName(e){const t=/^(\d{4,})_(.+)\.sql$/.exec(e);return t?{ordinal:Number(t[1]),tag:t[2]}:null}o(parseName,"parseName");async function sqlFiles(e){return(await promises.readdir(e).catch(()=>[])).filter(n=>n.endsWith(".sql")).sort()}o(sqlFiles,"sqlFiles");function normalizeGeneratedSql(e){return e.replaceAll('"public".',"")}o(normalizeGeneratedSql,"normalizeGeneratedSql");async function syncMigrations(e){const t=e.generatedDir??"backend/.drizzle",n=e.migrationsDir??"backend/migrations",g=await sqlFiles(path.join(e.root,t)),m=await sqlFiles(path.join(e.root,n)),l=new Map;let s=0;for(const r of m){const a=parseName(r);a&&(l.set(a.tag,r),s=Math.max(s,a.ordinal))}const i={copied:[],problems:[]};for(const r of g){const a=parseName(r);if(!a){i.problems.push(`${t}/${r}: not named <ordinal>_<tag>.sql`);continue}const u=normalizeGeneratedSql(await promises.readFile(path.join(e.root,t,r),"utf8")),d=l.get(a.tag);if(d){await promises.readFile(path.join(e.root,n,d),"utf8")!==u&&i.problems.push(`${n}/${d} differs from the regenerated ${r}. An applied migration is frozen \u2014 add a new one instead of editing it.`);continue}s+=1;const c=`${String(s).padStart(4,"0")}_${a.tag}.sql`;if(e.check){i.problems.push(`${n}/${c} is missing; run \`tego-plugin migrations sync\`.`);continue}await promises.writeFile(path.join(e.root,n,c),u,"utf8"),l.set(a.tag,c),i.copied.push({from:`${t}/${r}`,to:`${n}/${c}`})}return i}o(syncMigrations,"syncMigrations"),exports.normalizeGeneratedSql=normalizeGeneratedSql,exports.syncMigrations=syncMigrations;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
interface MigrationSyncOptions {
|
|
2
|
+
root: string;
|
|
3
|
+
/** drizzle-kit's `out`. Default `backend/.drizzle`. */
|
|
4
|
+
generatedDir?: string;
|
|
5
|
+
/** The manifest's migrations dir. Default `backend/migrations`. */
|
|
6
|
+
migrationsDir?: string;
|
|
7
|
+
/** Verify only (for `build` / CI): report what is missing or edited. */
|
|
8
|
+
check?: boolean;
|
|
9
|
+
}
|
|
10
|
+
interface MigrationSyncResult {
|
|
11
|
+
copied: {
|
|
12
|
+
from: string;
|
|
13
|
+
to: string;
|
|
14
|
+
}[];
|
|
15
|
+
problems: string[];
|
|
16
|
+
}
|
|
17
|
+
declare function normalizeGeneratedSql(sql: string): string;
|
|
18
|
+
declare function syncMigrations(options: MigrationSyncOptions): Promise<MigrationSyncResult>;
|
|
19
|
+
|
|
20
|
+
export { type MigrationSyncOptions, type MigrationSyncResult, normalizeGeneratedSql, syncMigrations };
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
interface MigrationSyncOptions {
|
|
2
|
+
root: string;
|
|
3
|
+
/** drizzle-kit's `out`. Default `backend/.drizzle`. */
|
|
4
|
+
generatedDir?: string;
|
|
5
|
+
/** The manifest's migrations dir. Default `backend/migrations`. */
|
|
6
|
+
migrationsDir?: string;
|
|
7
|
+
/** Verify only (for `build` / CI): report what is missing or edited. */
|
|
8
|
+
check?: boolean;
|
|
9
|
+
}
|
|
10
|
+
interface MigrationSyncResult {
|
|
11
|
+
copied: {
|
|
12
|
+
from: string;
|
|
13
|
+
to: string;
|
|
14
|
+
}[];
|
|
15
|
+
problems: string[];
|
|
16
|
+
}
|
|
17
|
+
declare function normalizeGeneratedSql(sql: string): string;
|
|
18
|
+
declare function syncMigrations(options: MigrationSyncOptions): Promise<MigrationSyncResult>;
|
|
19
|
+
|
|
20
|
+
export { type MigrationSyncOptions, type MigrationSyncResult, normalizeGeneratedSql, syncMigrations };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var w=Object.defineProperty;var o=(t,e)=>w(t,"name",{value:e,configurable:!0});import{readFile as m,writeFile as y,readdir as q}from"fs/promises";import{join as s}from"path";function f(t){const e=/^(\d{4,})_(.+)\.sql$/.exec(t);return e?{ordinal:Number(e[1]),tag:e[2]}:null}o(f,"parseName");async function p(t){return(await q(t).catch(()=>[])).filter(n=>n.endsWith(".sql")).sort()}o(p,"sqlFiles");function $(t){return t.replaceAll('"public".',"")}o($,"normalizeGeneratedSql");async function x(t){const e=t.generatedDir??"backend/.drizzle",n=t.migrationsDir??"backend/migrations",h=await p(s(t.root,e)),b=await p(s(t.root,n)),l=new Map;let c=0;for(const r of b){const a=f(r);a&&(l.set(a.tag,r),c=Math.max(c,a.ordinal))}const i={copied:[],problems:[]};for(const r of h){const a=f(r);if(!a){i.problems.push(`${e}/${r}: not named <ordinal>_<tag>.sql`);continue}const g=$(await m(s(t.root,e,r),"utf8")),u=l.get(a.tag);if(u){await m(s(t.root,n,u),"utf8")!==g&&i.problems.push(`${n}/${u} differs from the regenerated ${r}. An applied migration is frozen \u2014 add a new one instead of editing it.`);continue}c+=1;const d=`${String(c).padStart(4,"0")}_${a.tag}.sql`;if(t.check){i.problems.push(`${n}/${d} is missing; run \`tego-plugin migrations sync\`.`);continue}await y(s(t.root,n,d),g,"utf8"),l.set(a.tag,d),i.copied.push({from:`${e}/${r}`,to:`${n}/${d}`})}return i}o(x,"syncMigrations");export{$ as normalizeGeneratedSql,x as syncMigrations};
|
package/dist/pack.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var u=Object.defineProperty;var e=(r,n)=>u(r,"name",{value:n,configurable:!0});var
|
|
1
|
+
"use strict";var u=Object.defineProperty;var e=(r,n)=>u(r,"name",{value:n,configurable:!0});var chunk4LKRXDYY_cjs=require("./chunk-4LKRXDYY.cjs");require("./chunk-HZ4YWRYX.cjs"),require("./chunk-SKNPNPJP.cjs"),require("./chunk-45Y4CR4R.cjs"),require("./chunk-2P6UEAPV.cjs"),require("./chunk-N4SXZZPY.cjs"),require("./chunk-6HNG5OZI.cjs"),require("./chunk-AJY7ZHXK.cjs"),require("./chunk-OP64Y4IN.cjs"),Object.defineProperty(exports,"buildAgentTemplate",{enumerable:!0,get:e(function(){return chunk4LKRXDYY_cjs.buildAgentTemplate},"get")}),Object.defineProperty(exports,"buildPluginBackend",{enumerable:!0,get:e(function(){return chunk4LKRXDYY_cjs.buildPluginBackend},"get")}),Object.defineProperty(exports,"buildPluginTemplates",{enumerable:!0,get:e(function(){return chunk4LKRXDYY_cjs.buildPluginTemplates},"get")}),Object.defineProperty(exports,"lockPlugin",{enumerable:!0,get:e(function(){return chunk4LKRXDYY_cjs.lockPlugin},"get")}),Object.defineProperty(exports,"packPlugin",{enumerable:!0,get:e(function(){return chunk4LKRXDYY_cjs.packPlugin},"get")}),Object.defineProperty(exports,"readManifest",{enumerable:!0,get:e(function(){return chunk4LKRXDYY_cjs.readManifest},"get")}),Object.defineProperty(exports,"watchPluginFrontend",{enumerable:!0,get:e(function(){return chunk4LKRXDYY_cjs.watchPluginFrontend},"get")});
|
package/dist/pack.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { T as TegoPluginManifest, R as ResolvedBackendPart } from './manifest-types-
|
|
1
|
+
import { T as TegoPluginManifest, R as ResolvedBackendPart } from './manifest-types-CUTNfJTa.cjs';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Staging a `runtime: "python"` backend: source, locked wheels, and a lock
|
|
@@ -85,6 +85,11 @@ interface PackPluginOptions {
|
|
|
85
85
|
};
|
|
86
86
|
/** Where to report progress. Defaults to `console.log`. Pass `null` to mute. */
|
|
87
87
|
log?: ((message: string) => void) | null;
|
|
88
|
+
/**
|
|
89
|
+
* Run `tego-plugin doctor` first (default). Packing stops on the problems
|
|
90
|
+
* upload would refuse anyway; the rest are summarized, not fatal.
|
|
91
|
+
*/
|
|
92
|
+
doctor?: boolean;
|
|
88
93
|
}
|
|
89
94
|
interface PackedPlugin {
|
|
90
95
|
/** Absolute path of the archive. */
|
|
@@ -144,6 +149,7 @@ interface WatchPluginOptions {
|
|
|
144
149
|
* Never resolves — the caller is a foreground command the author interrupts.
|
|
145
150
|
*/
|
|
146
151
|
declare function watchPluginFrontend(options: WatchPluginOptions): Promise<never>;
|
|
152
|
+
declare function readManifest(root: string): Promise<TegoPluginManifest>;
|
|
147
153
|
interface BuildPluginBackendOptions {
|
|
148
154
|
/** Package root: the directory holding `tego.plugin.json`. */
|
|
149
155
|
root: string;
|
|
@@ -166,4 +172,4 @@ interface BuildPluginBackendOptions {
|
|
|
166
172
|
*/
|
|
167
173
|
declare function buildPluginBackend(part: ResolvedBackendPart, options: BuildPluginBackendOptions): Promise<void>;
|
|
168
174
|
|
|
169
|
-
export { type BuildPluginBackendOptions, type PackPluginOptions, type PackedPlugin, type WatchPluginOptions, buildAgentTemplate, buildPluginBackend, buildPluginTemplates, lockPlugin, packPlugin, watchPluginFrontend };
|
|
175
|
+
export { type BuildPluginBackendOptions, type PackPluginOptions, type PackedPlugin, type WatchPluginOptions, buildAgentTemplate, buildPluginBackend, buildPluginTemplates, lockPlugin, packPlugin, readManifest, watchPluginFrontend };
|
package/dist/pack.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { T as TegoPluginManifest, R as ResolvedBackendPart } from './manifest-types-
|
|
1
|
+
import { T as TegoPluginManifest, R as ResolvedBackendPart } from './manifest-types-CUTNfJTa.js';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Staging a `runtime: "python"` backend: source, locked wheels, and a lock
|
|
@@ -85,6 +85,11 @@ interface PackPluginOptions {
|
|
|
85
85
|
};
|
|
86
86
|
/** Where to report progress. Defaults to `console.log`. Pass `null` to mute. */
|
|
87
87
|
log?: ((message: string) => void) | null;
|
|
88
|
+
/**
|
|
89
|
+
* Run `tego-plugin doctor` first (default). Packing stops on the problems
|
|
90
|
+
* upload would refuse anyway; the rest are summarized, not fatal.
|
|
91
|
+
*/
|
|
92
|
+
doctor?: boolean;
|
|
88
93
|
}
|
|
89
94
|
interface PackedPlugin {
|
|
90
95
|
/** Absolute path of the archive. */
|
|
@@ -144,6 +149,7 @@ interface WatchPluginOptions {
|
|
|
144
149
|
* Never resolves — the caller is a foreground command the author interrupts.
|
|
145
150
|
*/
|
|
146
151
|
declare function watchPluginFrontend(options: WatchPluginOptions): Promise<never>;
|
|
152
|
+
declare function readManifest(root: string): Promise<TegoPluginManifest>;
|
|
147
153
|
interface BuildPluginBackendOptions {
|
|
148
154
|
/** Package root: the directory holding `tego.plugin.json`. */
|
|
149
155
|
root: string;
|
|
@@ -166,4 +172,4 @@ interface BuildPluginBackendOptions {
|
|
|
166
172
|
*/
|
|
167
173
|
declare function buildPluginBackend(part: ResolvedBackendPart, options: BuildPluginBackendOptions): Promise<void>;
|
|
168
174
|
|
|
169
|
-
export { type BuildPluginBackendOptions, type PackPluginOptions, type PackedPlugin, type WatchPluginOptions, buildAgentTemplate, buildPluginBackend, buildPluginTemplates, lockPlugin, packPlugin, watchPluginFrontend };
|
|
175
|
+
export { type BuildPluginBackendOptions, type PackPluginOptions, type PackedPlugin, type WatchPluginOptions, buildAgentTemplate, buildPluginBackend, buildPluginTemplates, lockPlugin, packPlugin, readManifest, watchPluginFrontend };
|
package/dist/pack.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export{buildAgentTemplate,buildPluginBackend,buildPluginTemplates,lockPlugin,packPlugin,watchPluginFrontend}from"./chunk-
|
|
1
|
+
export{buildAgentTemplate,buildPluginBackend,buildPluginTemplates,lockPlugin,packPlugin,readManifest,watchPluginFrontend}from"./chunk-FCYAAOHC.js";import"./chunk-I5Z3ECC4.js";import"./chunk-EIVA5BR6.js";import"./chunk-2NTAWYCG.js";import"./chunk-IVJECPGG.js";import"./chunk-INCA3GFW.js";import"./chunk-56QOZQTY.js";import"./chunk-VMCGDDGP.js";import"./chunk-SNUCO2MK.js";
|
package/dist/publish.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var $=Object.defineProperty;var s=(e,a)=>$(e,"name",{value:a,configurable:!0});var
|
|
1
|
+
"use strict";var $=Object.defineProperty;var s=(e,a)=>$(e,"name",{value:a,configurable:!0});var chunk4LKRXDYY_cjs=require("./chunk-4LKRXDYY.cjs");require("./chunk-HZ4YWRYX.cjs"),require("./chunk-SKNPNPJP.cjs"),require("./chunk-45Y4CR4R.cjs");var chunk2P6UEAPV_cjs=require("./chunk-2P6UEAPV.cjs");require("./chunk-N4SXZZPY.cjs"),require("./chunk-6HNG5OZI.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 chunk4LKRXDYY_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 l=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,l.uploadUrl,u,t),n("\u203A inspecting package");const c=await r("POST","/admin/runtime-plugins/inspect",{uploadToken:l.uploadToken});n(` ${c.pluginId}@${c.semanticVersion} \u2014 ${describeParts(c)}${c.isUpgrade?" (upgrade)":""}${c.requiresConfig?", needs config":""}`),n("\u203A finalizing release");const g=await r("POST","/admin/runtime-plugins/upload",{uploadToken:l.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=chunk2P6UEAPV_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:c,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,l){const c=await n(`${t}${API_PREFIX}${o}`,{method:u,headers:{authorization:`Bearer ${a}`,...l===void 0?{}:{"content-type":"application/json"}},...l===void 0?{}:{body:JSON.stringify(l)}});return unwrap(c,`${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;
|
package/dist/publish.d.cts
CHANGED
package/dist/publish.d.ts
CHANGED
package/dist/publish.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var h=Object.defineProperty;var o=(e,a)=>h(e,"name",{value:a,configurable:!0});import{packPlugin as v}from"./chunk-
|
|
1
|
+
var h=Object.defineProperty;var o=(e,a)=>h(e,"name",{value:a,configurable:!0});import{packPlugin as v}from"./chunk-FCYAAOHC.js";import"./chunk-I5Z3ECC4.js";import"./chunk-EIVA5BR6.js";import"./chunk-2NTAWYCG.js";import{resolvePluginScope as P}from"./chunk-IVJECPGG.js";import"./chunk-INCA3GFW.js";import"./chunk-56QOZQTY.js";import"./chunk-VMCGDDGP.js";import"./chunk-SNUCO2MK.js";import{readFile as w}from"fs/promises";import{basename as y}from"path";var I="/api/v1/tego-os";async function T(e){const a=e.log===null?()=>{}:e.log??(n=>console.log(n)),t=await v({root:e.root,log:a});return m(t,e)}o(T,"publishPlugin");async function m(e,a){const t=a.log===null?()=>{}:a.log??(p=>console.log(p)),n=a.fetchImpl??fetch,r=A(a.server,a.token,n),s=await w(e.file),c=y(e.file);t("\u203A presigning upload");const u=await r("POST","/admin/runtime-plugins/presign-stream",{filename:c,mimeType:"application/zip",size:s.byteLength});t(`\u203A uploading ${c} (${s.byteLength} bytes)`),await S(a.server,u.uploadUrl,s,n),t("\u203A inspecting package");const l=await r("POST","/admin/runtime-plugins/inspect",{uploadToken:u.uploadToken});t(` ${l.pluginId}@${l.semanticVersion} \u2014 ${b(l)}${l.isUpgrade?" (upgrade)":""}${l.requiresConfig?", needs config":""}`),t("\u203A finalizing release");const g=await r("POST","/admin/runtime-plugins/upload",{uploadToken:u.uploadToken,...a.meta});let i=g.release;t(` release ${i.id} (${i.status})`),(a.approve??!0)&&(t("\u203A approving release"),i=await r("POST",`/admin/runtime-plugins/releases/${encodeURIComponent(i.id)}/approve`,{}),t(` release ${i.id} (${i.status})`));let d=null;if(a.install??!0){const p=P(e.manifest),$=p==="avatar"?{releaseId:i.id,avatarIds:a.avatarIds??[]}:{releaseId:i.id};t(`\u203A installing for tenant (${p}-scoped)`),d=await r("POST","/admin/runtime-plugins/installs",$),k(d,t)}return{packed:e,preview:l,catalog:g.catalog,release:i,install:d}}o(m,"publishPackedPlugin");function b(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"}o(b,"describeParts");function k(e,a){const t=e.avatars;if(!t||t.attempted===0){a(` installed ${e.pluginId}@${e.version}`);return}const n=t.attempted-t.failures.length;a(` installed ${e.pluginId}@${e.version} \u2014 ${n}/${t.attempted} avatars`);for(const r of t.failures)a(` \u2717 ${r.avatarId}: ${r.message}`)}o(k,"reportInstall");function A(e,a,t){const n=e.replace(/\/+$/,"");return o(async function(s,c,u){const l=await t(`${n}${I}${c}`,{method:s,headers:{authorization:`Bearer ${a}`,...u===void 0?{}:{"content-type":"application/json"}},...u===void 0?{}:{body:JSON.stringify(u)}});return f(l,`${s} ${c}`)},"call")}o(A,"createCaller");async function S(e,a,t,n){const r=e.replace(/\/+$/,""),s=await n(`${r}${a}`,{method:"PUT",headers:{"content-type":"application/zip"},body:t});await f(s,"PUT upload")}o(S,"putArchive");async function f(e,a){let t;try{t=await e.json()}catch{t=null}if(!e.ok||!t?.success){const n=t?.error?.message??`HTTP ${e.status}`;throw new Error(`${a} failed: ${n}`)}return t.data}o(f,"unwrap");export{m as publishPackedPlugin,T as publishPlugin};
|
package/dist/react.cjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";var p=Object.defineProperty;var n=(e,t)=>p(e,"name",{value:t,configurable:!0});var react=require("react"),PluginApiError=class extends Error{static{n(this,"PluginApiError")}constructor(e,t,r,s={}){super(e),this.status=t,this.code=r,this.detail=s,this.name="PluginApiError"}status;code;detail};function toPluginApiError(e,t){const r=t&&typeof t=="object"?t.error:void 0;if(typeof r=="string")return new PluginApiError(r,e,void 0);if(r&&typeof r=="object"){const{code:s,message:i,detail:o}=r;return new PluginApiError(typeof i=="string"?i:`HTTP ${e}`,e,typeof s=="string"?s:void 0,o&&typeof o=="object"?o:{})}return new PluginApiError(`HTTP ${e}`,e,void 0)}n(toPluginApiError,"toPluginApiError");function createApiClient(e){const t=n(async(r,s,i)=>{const o=await e.request(s,i===void 0?{method:r}:{method:r,headers:{"content-type":"application/json"},body:JSON.stringify(i)}),u=await o.text();let c=null;try{c=u?JSON.parse(u):null}catch{c=u||null}if(!o.ok)throw toPluginApiError(o.status,c);return c},"send");return{get:n(r=>t("GET",r),"get"),post:n((r,s)=>t("POST",r,s??{}),"post"),put:n((r,s)=>t("PUT",r,s),"put"),patch:n((r,s)=>t("PATCH",r,s),"patch"),delete:n(r=>t("DELETE",r),"delete")}}n(createApiClient,"createApiClient");function withQuery(e,t){const r=new URLSearchParams;for(const[i,o]of Object.entries(t))o!==void 0&&o!==""&&r.set(i,String(o));const s=r.toString();return s?`${e}?${s}`:e}n(withQuery,"withQuery");function describeApiError(e,t){return e instanceof PluginApiError?e.code?{key:`${t}.errors.${e.code}`,message:e.message}:{message:e.message}:{message:e instanceof Error?e.message:String(e)}}n(describeApiError,"describeApiError");var HostContext=react.createContext(null);function HostProvider({value:e,children:t}){return react.createElement(HostContext.Provider,{value:e},t)}n(HostProvider,"HostProvider");function useHost(){const e=react.useContext(HostContext);if(!e)throw new Error("useHost() outside <HostProvider>");return e}n(useHost,"useHost");function usePluginRoute(){const{route:e}=useHost();return react.useSyncExternalStore(t=>e.subscribe(t),()=>e.current())}n(usePluginRoute,"usePluginRoute");function useLiveUpdates(e,t={}){const{events:r}=useHost(),s=react.useRef({onChange:e,filter:t.filter});s.current={onChange:e,filter:t.filter};const i=t.waitMs??400;react.useEffect(()=>{let o=[],u;const c=r.subscribe(a=>{s.current.filter&&!s.current.filter(a)||(o.push(a),!u&&(u=setTimeout(()=>{u=void 0;const l=o;o=[],s.current.onChange(l)},i)))});return()=>{c(),u&&clearTimeout(u)}},[r,i])}n(useLiveUpdates,"useLiveUpdates");var PluginErrorBoundary=class extends react.Component{static{n(this,"PluginErrorBoundary")}state={error:null};static getDerivedStateFromError(e){return{error:e instanceof Error?e:new Error(String(e))}}componentDidCatch(e,t){this.props.onError?.(e,t)}reset=n(()=>this.setState({error:null}),"reset");render(){return this.state.error?this.props.fallback(this.state.error,this.reset):this.props.children??null}};exports.HostProvider=HostProvider,exports.PluginApiError=PluginApiError,exports.PluginErrorBoundary=PluginErrorBoundary,exports.createApiClient=createApiClient,exports.describeApiError=describeApiError,exports.toPluginApiError=toPluginApiError,exports.useHost=useHost,exports.useLiveUpdates=useLiveUpdates,exports.usePluginRoute=usePluginRoute,exports.withQuery=withQuery;
|
package/dist/react.d.cts
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { ReactNode, Component, ErrorInfo } from 'react';
|
|
3
|
+
import { PluginApiClient, PluginHostContext, PluginEvent, PluginRoute } from './frontend.cjs';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Calls to the plugin's own backend through `ctx.api`, with errors that keep
|
|
7
|
+
* what the backend said.
|
|
8
|
+
*
|
|
9
|
+
* `ctx.api.json` throws a bare `Error('<method> <path>: <status>')` and drops
|
|
10
|
+
* the body, so a screen cannot tell "that note is locked" from "the server
|
|
11
|
+
* fell over". This keeps the code for translation and the message for the
|
|
12
|
+
* fallback. Two shapes arrive here: the plugin backend's
|
|
13
|
+
* `{ error: { code, message, detail? } }` (what `pluginErrorHandler` writes)
|
|
14
|
+
* and the gateway's `{ success: false, error: string | { message } }`.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
declare class PluginApiError extends Error {
|
|
18
|
+
readonly status: number;
|
|
19
|
+
readonly code: string | undefined;
|
|
20
|
+
readonly detail: Record<string, unknown>;
|
|
21
|
+
constructor(message: string, status: number, code: string | undefined, detail?: Record<string, unknown>);
|
|
22
|
+
}
|
|
23
|
+
/** The error a failed response carries, whichever side wrote it. */
|
|
24
|
+
declare function toPluginApiError(status: number, body: unknown): PluginApiError;
|
|
25
|
+
interface PluginApi {
|
|
26
|
+
get<T>(path: string): Promise<T>;
|
|
27
|
+
/** A POST without a body still sends `{}`: validators read JSON on every write. */
|
|
28
|
+
post<T>(path: string, body?: unknown): Promise<T>;
|
|
29
|
+
put<T>(path: string, body: unknown): Promise<T>;
|
|
30
|
+
patch<T>(path: string, body: unknown): Promise<T>;
|
|
31
|
+
delete<T>(path: string): Promise<T>;
|
|
32
|
+
}
|
|
33
|
+
declare function createApiClient(client: PluginApiClient): PluginApi;
|
|
34
|
+
/** `path?a=1&b=x`, leaving out empty values. */
|
|
35
|
+
declare function withQuery(path: string, params: Record<string, string | number | undefined>): string;
|
|
36
|
+
/**
|
|
37
|
+
* What to tell the user about a failed call: the translation key
|
|
38
|
+
* `<namespace>.errors.<code>` when the backend sent a code, and the backend's
|
|
39
|
+
* own sentence as the fallback.
|
|
40
|
+
*
|
|
41
|
+
* ```ts
|
|
42
|
+
* const { key, message } = describeApiError(error, 'notes');
|
|
43
|
+
* return key ? t(key, { defaultValue: message }) : message;
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
declare function describeApiError(error: unknown, namespace: string): {
|
|
47
|
+
key?: string;
|
|
48
|
+
message: string;
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
/** Makes `ctx` available to `useHost` / `usePluginRoute` below it. */
|
|
52
|
+
declare function HostProvider({ value, children, }: {
|
|
53
|
+
value: PluginHostContext;
|
|
54
|
+
children?: ReactNode;
|
|
55
|
+
}): react.FunctionComponentElement<react.ProviderProps<PluginHostContext | null>>;
|
|
56
|
+
declare function useHost(): PluginHostContext;
|
|
57
|
+
/**
|
|
58
|
+
* The in-plugin route, re-rendering on every host navigation.
|
|
59
|
+
*
|
|
60
|
+
* The shell does not remount the page when only the path below `/p/<id>`
|
|
61
|
+
* changes, so reading `ctx.route.current()` once is a stale page.
|
|
62
|
+
*/
|
|
63
|
+
declare function usePluginRoute(): PluginRoute;
|
|
64
|
+
/**
|
|
65
|
+
* Calls `onChange` when the plugin's backend publishes events, at most once
|
|
66
|
+
* per `waitMs` (a burst of writes is one refresh). Pass a stable callback,
|
|
67
|
+
* e.g. `() => queryClient.invalidateQueries({ queryKey: ['notes'] })`.
|
|
68
|
+
*
|
|
69
|
+
* `filter` limits it to some event names. The stream may be down: keep a slow
|
|
70
|
+
* `refetchInterval` as a fallback (faster while `ctx.events.connected()` is false).
|
|
71
|
+
*/
|
|
72
|
+
declare function useLiveUpdates(onChange: (events: PluginEvent[]) => void, options?: {
|
|
73
|
+
waitMs?: number;
|
|
74
|
+
filter?: (event: PluginEvent) => boolean;
|
|
75
|
+
}): void;
|
|
76
|
+
interface BoundaryProps {
|
|
77
|
+
/** What to show instead of the crashed tree; `reset` renders the children again. */
|
|
78
|
+
fallback: (error: Error, reset: () => void) => ReactNode;
|
|
79
|
+
onError?(error: Error, info: ErrorInfo): void;
|
|
80
|
+
children?: ReactNode;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* The plugin's own error boundary. The shell's boundary sits outside this
|
|
84
|
+
* React root and never sees an error thrown inside it: without one a render
|
|
85
|
+
* error is a blank page that reads as the platform losing the plugin.
|
|
86
|
+
*/
|
|
87
|
+
declare class PluginErrorBoundary extends Component<BoundaryProps, {
|
|
88
|
+
error: Error | null;
|
|
89
|
+
}> {
|
|
90
|
+
state: {
|
|
91
|
+
error: Error | null;
|
|
92
|
+
};
|
|
93
|
+
static getDerivedStateFromError(error: unknown): {
|
|
94
|
+
error: Error;
|
|
95
|
+
};
|
|
96
|
+
componentDidCatch(error: Error, info: ErrorInfo): void;
|
|
97
|
+
private readonly reset;
|
|
98
|
+
render(): ReactNode;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export { HostProvider, type PluginApi, PluginApiError, PluginErrorBoundary, createApiClient, describeApiError, toPluginApiError, useHost, useLiveUpdates, usePluginRoute, withQuery };
|
package/dist/react.d.ts
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { ReactNode, Component, ErrorInfo } from 'react';
|
|
3
|
+
import { PluginApiClient, PluginHostContext, PluginEvent, PluginRoute } from './frontend.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Calls to the plugin's own backend through `ctx.api`, with errors that keep
|
|
7
|
+
* what the backend said.
|
|
8
|
+
*
|
|
9
|
+
* `ctx.api.json` throws a bare `Error('<method> <path>: <status>')` and drops
|
|
10
|
+
* the body, so a screen cannot tell "that note is locked" from "the server
|
|
11
|
+
* fell over". This keeps the code for translation and the message for the
|
|
12
|
+
* fallback. Two shapes arrive here: the plugin backend's
|
|
13
|
+
* `{ error: { code, message, detail? } }` (what `pluginErrorHandler` writes)
|
|
14
|
+
* and the gateway's `{ success: false, error: string | { message } }`.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
declare class PluginApiError extends Error {
|
|
18
|
+
readonly status: number;
|
|
19
|
+
readonly code: string | undefined;
|
|
20
|
+
readonly detail: Record<string, unknown>;
|
|
21
|
+
constructor(message: string, status: number, code: string | undefined, detail?: Record<string, unknown>);
|
|
22
|
+
}
|
|
23
|
+
/** The error a failed response carries, whichever side wrote it. */
|
|
24
|
+
declare function toPluginApiError(status: number, body: unknown): PluginApiError;
|
|
25
|
+
interface PluginApi {
|
|
26
|
+
get<T>(path: string): Promise<T>;
|
|
27
|
+
/** A POST without a body still sends `{}`: validators read JSON on every write. */
|
|
28
|
+
post<T>(path: string, body?: unknown): Promise<T>;
|
|
29
|
+
put<T>(path: string, body: unknown): Promise<T>;
|
|
30
|
+
patch<T>(path: string, body: unknown): Promise<T>;
|
|
31
|
+
delete<T>(path: string): Promise<T>;
|
|
32
|
+
}
|
|
33
|
+
declare function createApiClient(client: PluginApiClient): PluginApi;
|
|
34
|
+
/** `path?a=1&b=x`, leaving out empty values. */
|
|
35
|
+
declare function withQuery(path: string, params: Record<string, string | number | undefined>): string;
|
|
36
|
+
/**
|
|
37
|
+
* What to tell the user about a failed call: the translation key
|
|
38
|
+
* `<namespace>.errors.<code>` when the backend sent a code, and the backend's
|
|
39
|
+
* own sentence as the fallback.
|
|
40
|
+
*
|
|
41
|
+
* ```ts
|
|
42
|
+
* const { key, message } = describeApiError(error, 'notes');
|
|
43
|
+
* return key ? t(key, { defaultValue: message }) : message;
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
declare function describeApiError(error: unknown, namespace: string): {
|
|
47
|
+
key?: string;
|
|
48
|
+
message: string;
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
/** Makes `ctx` available to `useHost` / `usePluginRoute` below it. */
|
|
52
|
+
declare function HostProvider({ value, children, }: {
|
|
53
|
+
value: PluginHostContext;
|
|
54
|
+
children?: ReactNode;
|
|
55
|
+
}): react.FunctionComponentElement<react.ProviderProps<PluginHostContext | null>>;
|
|
56
|
+
declare function useHost(): PluginHostContext;
|
|
57
|
+
/**
|
|
58
|
+
* The in-plugin route, re-rendering on every host navigation.
|
|
59
|
+
*
|
|
60
|
+
* The shell does not remount the page when only the path below `/p/<id>`
|
|
61
|
+
* changes, so reading `ctx.route.current()` once is a stale page.
|
|
62
|
+
*/
|
|
63
|
+
declare function usePluginRoute(): PluginRoute;
|
|
64
|
+
/**
|
|
65
|
+
* Calls `onChange` when the plugin's backend publishes events, at most once
|
|
66
|
+
* per `waitMs` (a burst of writes is one refresh). Pass a stable callback,
|
|
67
|
+
* e.g. `() => queryClient.invalidateQueries({ queryKey: ['notes'] })`.
|
|
68
|
+
*
|
|
69
|
+
* `filter` limits it to some event names. The stream may be down: keep a slow
|
|
70
|
+
* `refetchInterval` as a fallback (faster while `ctx.events.connected()` is false).
|
|
71
|
+
*/
|
|
72
|
+
declare function useLiveUpdates(onChange: (events: PluginEvent[]) => void, options?: {
|
|
73
|
+
waitMs?: number;
|
|
74
|
+
filter?: (event: PluginEvent) => boolean;
|
|
75
|
+
}): void;
|
|
76
|
+
interface BoundaryProps {
|
|
77
|
+
/** What to show instead of the crashed tree; `reset` renders the children again. */
|
|
78
|
+
fallback: (error: Error, reset: () => void) => ReactNode;
|
|
79
|
+
onError?(error: Error, info: ErrorInfo): void;
|
|
80
|
+
children?: ReactNode;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* The plugin's own error boundary. The shell's boundary sits outside this
|
|
84
|
+
* React root and never sees an error thrown inside it: without one a render
|
|
85
|
+
* error is a blank page that reads as the platform losing the plugin.
|
|
86
|
+
*/
|
|
87
|
+
declare class PluginErrorBoundary extends Component<BoundaryProps, {
|
|
88
|
+
error: Error | null;
|
|
89
|
+
}> {
|
|
90
|
+
state: {
|
|
91
|
+
error: Error | null;
|
|
92
|
+
};
|
|
93
|
+
static getDerivedStateFromError(error: unknown): {
|
|
94
|
+
error: Error;
|
|
95
|
+
};
|
|
96
|
+
componentDidCatch(error: Error, info: ErrorInfo): void;
|
|
97
|
+
private readonly reset;
|
|
98
|
+
render(): ReactNode;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export { HostProvider, type PluginApi, PluginApiError, PluginErrorBoundary, createApiClient, describeApiError, toPluginApiError, useHost, useLiveUpdates, usePluginRoute, withQuery };
|
package/dist/react.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var h=Object.defineProperty;var s=(e,t)=>h(e,"name",{value:t,configurable:!0});import{createContext as E,createElement as m,useContext as v,useSyncExternalStore as P,useRef as w,useEffect as y,Component as S}from"react";var a=class extends Error{static{s(this,"PluginApiError")}constructor(e,t,r,n={}){super(e),this.status=t,this.code=r,this.detail=n,this.name="PluginApiError"}status;code;detail};function d(e,t){const r=t&&typeof t=="object"?t.error:void 0;if(typeof r=="string")return new a(r,e,void 0);if(r&&typeof r=="object"){const{code:n,message:i,detail:o}=r;return new a(typeof i=="string"?i:`HTTP ${e}`,e,typeof n=="string"?n:void 0,o&&typeof o=="object"?o:{})}return new a(`HTTP ${e}`,e,void 0)}s(d,"toPluginApiError");function b(e){const t=s(async(r,n,i)=>{const o=await e.request(n,i===void 0?{method:r}:{method:r,headers:{"content-type":"application/json"},body:JSON.stringify(i)}),c=await o.text();let u=null;try{u=c?JSON.parse(c):null}catch{u=c||null}if(!o.ok)throw d(o.status,u);return u},"send");return{get:s(r=>t("GET",r),"get"),post:s((r,n)=>t("POST",r,n??{}),"post"),put:s((r,n)=>t("PUT",r,n),"put"),patch:s((r,n)=>t("PATCH",r,n),"patch"),delete:s(r=>t("DELETE",r),"delete")}}s(b,"createApiClient");function T(e,t){const r=new URLSearchParams;for(const[i,o]of Object.entries(t))o!==void 0&&o!==""&&r.set(i,String(o));const n=r.toString();return n?`${e}?${n}`:e}s(T,"withQuery");function x(e,t){return e instanceof a?e.code?{key:`${t}.errors.${e.code}`,message:e.message}:{message:e.message}:{message:e instanceof Error?e.message:String(e)}}s(x,"describeApiError");var p=E(null);function H({value:e,children:t}){return m(p.Provider,{value:e},t)}s(H,"HostProvider");function l(){const e=v(p);if(!e)throw new Error("useHost() outside <HostProvider>");return e}s(l,"useHost");function C(){const{route:e}=l();return P(t=>e.subscribe(t),()=>e.current())}s(C,"usePluginRoute");function A(e,t={}){const{events:r}=l(),n=w({onChange:e,filter:t.filter});n.current={onChange:e,filter:t.filter};const i=t.waitMs??400;y(()=>{let o=[],c;const u=r.subscribe(f=>{n.current.filter&&!n.current.filter(f)||(o.push(f),!c&&(c=setTimeout(()=>{c=void 0;const g=o;o=[],n.current.onChange(g)},i)))});return()=>{u(),c&&clearTimeout(c)}},[r,i])}s(A,"useLiveUpdates");var $=class extends S{static{s(this,"PluginErrorBoundary")}state={error:null};static getDerivedStateFromError(e){return{error:e instanceof Error?e:new Error(String(e))}}componentDidCatch(e,t){this.props.onError?.(e,t)}reset=s(()=>this.setState({error:null}),"reset");render(){return this.state.error?this.props.fallback(this.state.error,this.reset):this.props.children??null}};export{H as HostProvider,a as PluginApiError,$ as PluginErrorBoundary,b as createApiClient,x as describeApiError,d as toPluginApiError,l as useHost,A as useLiveUpdates,C as usePluginRoute,T as withQuery};
|