@kb-labs/marketplace-registry-entry 2.109.0 → 2.111.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/dist/commands/deprecate.d.ts +1 -3
- package/dist/commands/deprecate.js +6 -6
- package/dist/commands/deprecate.js.map +1 -1
- package/dist/commands/publish.d.ts +10 -3
- package/dist/commands/publish.js +10 -10
- package/dist/commands/publish.js.map +1 -1
- package/dist/commands/share.d.ts +6 -3
- package/dist/commands/share.js +9 -9
- package/dist/commands/share.js.map +1 -1
- package/dist/commands/yank.d.ts +1 -3
- package/dist/commands/yank.js +6 -6
- package/dist/commands/yank.js.map +1 -1
- package/package.json +1 -1
|
@@ -5,8 +5,6 @@ interface DeprecateFlags {
|
|
|
5
5
|
message?: string;
|
|
6
6
|
json?: boolean;
|
|
7
7
|
}
|
|
8
|
-
declare const _default: _kb_labs_shared_command_kit.CommandHandlerV3<unknown, CLIInput<DeprecateFlags>,
|
|
9
|
-
exitCode: number;
|
|
10
|
-
}>;
|
|
8
|
+
declare const _default: _kb_labs_shared_command_kit.CommandHandlerV3<unknown, CLIInput<DeprecateFlags>, unknown>;
|
|
11
9
|
|
|
12
10
|
export { _default as default };
|
|
@@ -99,11 +99,11 @@ var deprecate_default = defineCommand({
|
|
|
99
99
|
const t0 = Date.now();
|
|
100
100
|
if (!pkg) {
|
|
101
101
|
validationError(ctx, "Package spec is required", 'Usage: kb marketplace deprecate kb:handle/name [--message "reason"]', flags.json);
|
|
102
|
-
return {
|
|
102
|
+
return { ok: false, error: "Package spec is required" };
|
|
103
103
|
}
|
|
104
104
|
if (!pkg.startsWith("kb:")) {
|
|
105
105
|
validationError(ctx, "Package must be a kb: spec", "Example: kb:kirill/my-plugin", flags.json);
|
|
106
|
-
return {
|
|
106
|
+
return { ok: false, error: "Package must be a kb: spec" };
|
|
107
107
|
}
|
|
108
108
|
const sliced = pkg.slice(3);
|
|
109
109
|
const slashIdx = sliced.indexOf("/");
|
|
@@ -111,13 +111,13 @@ var deprecate_default = defineCommand({
|
|
|
111
111
|
const name = slashIdx > 0 ? sliced.slice(slashIdx + 1) : "";
|
|
112
112
|
if (!handle || !name) {
|
|
113
113
|
validationError(ctx, "Invalid kb: spec \u2014 expected kb:handle/name", void 0, flags.json);
|
|
114
|
-
return {
|
|
114
|
+
return { ok: false, error: "Invalid kb: spec" };
|
|
115
115
|
}
|
|
116
116
|
try {
|
|
117
117
|
await registryPost(`/packages/${handle}/${encodeURIComponent(name)}/deprecate`, { message: flags.message });
|
|
118
118
|
if (flags.json) {
|
|
119
119
|
ctx.ui?.json?.({ deprecated: true, pkg });
|
|
120
|
-
return {
|
|
120
|
+
return { ok: true };
|
|
121
121
|
}
|
|
122
122
|
const items = [
|
|
123
123
|
"Hidden from the marketplace catalog",
|
|
@@ -132,10 +132,10 @@ var deprecate_default = defineCommand({
|
|
|
132
132
|
hint: "To block a specific version only, use kb marketplace yank instead",
|
|
133
133
|
timing: Date.now() - t0
|
|
134
134
|
});
|
|
135
|
-
return {
|
|
135
|
+
return { ok: true };
|
|
136
136
|
} catch (err) {
|
|
137
137
|
handleError(ctx, err, flags.json);
|
|
138
|
-
return {
|
|
138
|
+
return { ok: false, error: err instanceof Error ? err.message : String(err) };
|
|
139
139
|
}
|
|
140
140
|
}
|
|
141
141
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/registry-http.ts","../../src/commands/deprecate.ts"],"names":[],"mappings":"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","file":"deprecate.js","sourcesContent":["/**\n * HTTP client for KB Labs Registry service.\n *\n * Credential provider chain (in priority order):\n * 1. KB_REGISTRY_URL + KB_REGISTRY_TOKEN — explicit registry URL (CI/CD, closed-loop mirror)\n * 2. KB_GATEWAY_URL + KB_REGISTRY_TOKEN — legacy CI/CD (derives registry URL from gateway)\n * 3. ~/.kb/credentials.json + KB_REGISTRY_URL — credentials file with explicit registry URL override\n * 4. ~/.kb/credentials.json fully — credentials file, derives registry URL from gatewayUrl\n * 5. Error — \"Run: kb auth login\"\n *\n * KB_REGISTRY_URL decouples the data layer (where the registry lives) from the execution\n * layer (which gateway runs the CLI command). Useful when the registry is behind a different\n * URL than the execution gateway — e.g. closed-loop mirrors or local dev pointing to prod registry.\n *\n * Token auto-refresh: if accessToken is within 60s of expiry, exchanges refreshToken\n * via POST /auth/refresh and overwrites ~/.kb/credentials.json (chmod 600).\n */\n\nimport { readFile, writeFile, chmod } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { homedir } from 'node:os';\nimport { useEnv } from '@kb-labs/sdk';\n\nconst CREDENTIALS_PATH = join(homedir(), '.kb', 'credentials.json');\nconst REGISTRY_GATEWAY_PREFIX = '/api/v1/registry';\nconst FETCH_TIMEOUT_MS = 60_000;\nconst EXPIRY_BUFFER_MS = 60_000;\n\ninterface ResolvedAuth {\n token: string;\n baseUrl: string; // full registry base URL including /api/v1/registry prefix\n handle: string;\n}\n\ninterface StoredCredentials {\n gatewayUrl: string;\n accessToken: string;\n refreshToken: string;\n expiresAt: number;\n handle?: string;\n namespaceId?: string;\n}\n\n/**\n * Resolve registry base URL from env vars only (used when a token is passed explicitly).\n * Priority: KB_REGISTRY_URL → KB_GATEWAY_URL → localhost fallback.\n */\nfunction resolveBaseUrlFromEnv(): string {\n const regUrl = useEnv('KB_REGISTRY_URL');\n const gateway = useEnv('KB_GATEWAY_URL');\n if (regUrl) { return regUrl.replace(/\\/$/, ''); }\n if (gateway) { return `${gateway.replace(/\\/$/, '')}${REGISTRY_GATEWAY_PREFIX}`; }\n return `http://127.0.0.1:4000${REGISTRY_GATEWAY_PREFIX}`;\n}\n\nasync function resolveAuth(): Promise<ResolvedAuth> {\n const envToken = useEnv('KB_REGISTRY_TOKEN');\n const envRegUrl = useEnv('KB_REGISTRY_URL'); // explicit registry base URL (data layer)\n const envGateway = useEnv('KB_GATEWAY_URL'); // legacy: derive registry URL from gateway\n const envHandle = useEnv('KB_REGISTRY_AUTHOR_HANDLE');\n\n // 1. Explicit registry URL + token (CI/CD, closed-loop mirror)\n if (envToken && envRegUrl) {\n return { token: envToken, baseUrl: envRegUrl.replace(/\\/$/, ''), handle: envHandle ?? '' };\n }\n\n // 2. Legacy: token + gateway URL → derive registry base URL\n if (envToken && envGateway) {\n return {\n token: envToken,\n baseUrl: `${envGateway.replace(/\\/$/, '')}${REGISTRY_GATEWAY_PREFIX}`,\n handle: envHandle ?? '',\n };\n }\n\n // 3–4. ~/.kb/credentials.json\n let creds: StoredCredentials;\n try {\n creds = JSON.parse(await readFile(CREDENTIALS_PATH, 'utf-8')) as StoredCredentials;\n } catch {\n throw new Error(\n 'Not authenticated. Run:\\n kb auth login --gateway-url <url> --email <email> --password <password>\\n kb auth register --gateway-url <url> --name <name> --namespace-id <ns>\\n kb auth login --gateway-url <url> --client-id <id> --client-secret <secret>',\n );\n }\n\n // Auto-refresh if token is expired or close to expiry\n if (Date.now() >= creds.expiresAt - EXPIRY_BUFFER_MS) {\n const res = await fetch(`${creds.gatewayUrl}/auth/refresh`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ refreshToken: creds.refreshToken }),\n });\n if (!res.ok) {\n throw new Error('Session expired. Run: kb auth login --gateway-url <url> --client-id <id> --client-secret <secret>');\n }\n const refreshed = await res.json() as { accessToken: string; refreshToken: string; expiresIn: number };\n creds = {\n ...creds,\n accessToken: refreshed.accessToken,\n refreshToken: refreshed.refreshToken,\n expiresAt: Date.now() + refreshed.expiresIn * 1000,\n };\n await writeFile(CREDENTIALS_PATH, JSON.stringify(creds, null, 2), 'utf-8');\n await chmod(CREDENTIALS_PATH, 0o600);\n }\n\n if (!creds.handle) {\n throw new Error(\n 'Author handle not set in credentials. Re-run:\\n kb auth login --gateway-url <url> --client-id <id> --client-secret <secret>',\n );\n }\n\n // 3. credentials + KB_REGISTRY_URL override (execution gateway ≠ registry URL)\n // 4. credentials fully (gatewayUrl used to derive registry base URL)\n const baseUrl = envRegUrl\n ? envRegUrl.replace(/\\/$/, '')\n : `${creds.gatewayUrl.replace(/\\/$/, '')}${REGISTRY_GATEWAY_PREFIX}`;\n\n return { token: creds.accessToken, baseUrl, handle: creds.handle };\n}\n\n/**\n * Resolve the author handle from the credential provider chain.\n * Used when the handle is needed explicitly (e.g. for URL path construction).\n */\nexport async function resolveRegistryHandle(): Promise<string> {\n const auth = await resolveAuth();\n return auth.handle;\n}\n\nexport async function registryPost<T = unknown>(\n path: string,\n body: Record<string, unknown>,\n token?: string,\n): Promise<T> {\n const auth = token\n ? { token, baseUrl: resolveBaseUrlFromEnv() }\n : await resolveAuth();\n\n const url = `${auth.baseUrl}${path}`;\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);\n try {\n const res = await fetch(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${auth.token}` },\n body: JSON.stringify(body),\n signal: controller.signal,\n });\n if (!res.ok) {\n const text = await res.text();\n throw new Error(`Registry ${path} failed (${res.status}): ${text}`);\n }\n if (res.status === 204) { return undefined as T; }\n return await res.json() as T;\n } catch (err) {\n if ((err as Error).name === 'AbortError') {\n throw new Error('Registry request timed out. Is the gateway reachable?');\n }\n throw err;\n } finally {\n clearTimeout(timer);\n }\n}\n\nexport async function registryPostMultipart<T = unknown>(\n path: string,\n tarball: Buffer,\n fields: Record<string, string>,\n token?: string,\n authorHandle?: string,\n): Promise<T> {\n const auth = token\n ? {\n token,\n baseUrl: resolveBaseUrlFromEnv(),\n handle: authorHandle ?? useEnv('KB_REGISTRY_AUTHOR_HANDLE') ?? '',\n }\n : await resolveAuth();\n\n const url = `${auth.baseUrl}${path}`;\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);\n try {\n const form = new FormData();\n form.append('tarball', new Blob([tarball], { type: 'application/octet-stream' }), 'package.tgz');\n for (const [k, v] of Object.entries(fields)) { form.append(k, v); }\n\n const handleHeader: Record<string, string> = auth.handle ? { 'X-Author-Handle': auth.handle } : {};\n\n const res = await fetch(url, {\n method: 'POST',\n headers: { Authorization: `Bearer ${auth.token}`, ...handleHeader },\n body: form,\n signal: controller.signal,\n });\n if (!res.ok) {\n const text = await res.text();\n throw new Error(`Registry publish failed (${res.status}): ${text}`);\n }\n return await res.json() as T;\n } catch (err) {\n if ((err as Error).name === 'AbortError') {\n throw new Error('Registry publish timed out.');\n }\n throw err;\n } finally {\n clearTimeout(timer);\n }\n}\n\nexport async function registryPatch<T = unknown>(\n path: string,\n body: Record<string, unknown>,\n token?: string,\n): Promise<T> {\n const auth = token\n ? { token, baseUrl: resolveBaseUrlFromEnv() }\n : await resolveAuth();\n\n const url = `${auth.baseUrl}${path}`;\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);\n try {\n const res = await fetch(url, {\n method: 'PATCH',\n headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${auth.token}` },\n body: JSON.stringify(body),\n signal: controller.signal,\n });\n if (!res.ok) {\n const text = await res.text();\n throw new Error(`Registry ${path} failed (${res.status}): ${text}`);\n }\n if (res.status === 204) { return undefined as T; }\n return await res.json() as T;\n } catch (err) {\n if ((err as Error).name === 'AbortError') {\n throw new Error('Registry request timed out.');\n }\n throw err;\n } finally {\n clearTimeout(timer);\n }\n}\n","import { defineCommand, handleError, validationError, type CLIInput, type PluginContextV3 } from '@kb-labs/sdk';\nimport { registryPost } from '../registry-http.js';\n\ninterface DeprecateFlags {\n message?: string;\n json?: boolean;\n}\n\nexport default defineCommand<unknown, CLIInput<DeprecateFlags>, { exitCode: number }>({\n id: 'marketplace:deprecate',\n description: 'Deprecate a package (removed from catalog, install shows warning)',\n\n handler: {\n async execute(ctx: PluginContextV3, input: CLIInput<DeprecateFlags>): Promise<{ exitCode: number }> {\n const { flags = {}, argv = [] } = input;\n const pkg = argv[0];\n const t0 = Date.now();\n\n if (!pkg) {\n validationError(ctx, 'Package spec is required', 'Usage: kb marketplace deprecate kb:handle/name [--message \"reason\"]', flags.json);\n return { exitCode: 1 };\n }\n\n if (!pkg.startsWith('kb:')) {\n validationError(ctx, 'Package must be a kb: spec', 'Example: kb:kirill/my-plugin', flags.json);\n return { exitCode: 1 };\n }\n\n const sliced = pkg.slice(3);\n const slashIdx = sliced.indexOf('/');\n const handle = slashIdx > 0 ? sliced.slice(0, slashIdx) : '';\n const name = slashIdx > 0 ? sliced.slice(slashIdx + 1) : '';\n if (!handle || !name) {\n validationError(ctx, 'Invalid kb: spec — expected kb:handle/name', undefined, flags.json);\n return { exitCode: 1 };\n }\n\n try {\n await registryPost(`/packages/${handle}/${encodeURIComponent(name)}/deprecate`, { message: flags.message });\n\n if (flags.json) {\n ctx.ui?.json?.({ deprecated: true, pkg });\n return { exitCode: 0 };\n }\n\n const items = [\n 'Hidden from the marketplace catalog',\n 'Existing installations still work but show a deprecation warning',\n 'New installs are allowed but show a warning',\n ];\n if (flags.message) {\n items.push(`Message: ${flags.message}`);\n }\n\n ctx.ui?.success?.(`${pkg} deprecated`, {\n sections: [{ header: 'What this means', items }],\n hint: 'To block a specific version only, use kb marketplace yank instead',\n timing: Date.now() - t0,\n });\n\n return { exitCode: 0 };\n } catch (err) {\n handleError(ctx, err, flags.json);\n return { exitCode: 1 };\n }\n },\n },\n});\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/registry-http.ts","../../src/commands/deprecate.ts"],"names":[],"mappings":"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","file":"deprecate.js","sourcesContent":["/**\n * HTTP client for KB Labs Registry service.\n *\n * Credential provider chain (in priority order):\n * 1. KB_REGISTRY_URL + KB_REGISTRY_TOKEN — explicit registry URL (CI/CD, closed-loop mirror)\n * 2. KB_GATEWAY_URL + KB_REGISTRY_TOKEN — legacy CI/CD (derives registry URL from gateway)\n * 3. ~/.kb/credentials.json + KB_REGISTRY_URL — credentials file with explicit registry URL override\n * 4. ~/.kb/credentials.json fully — credentials file, derives registry URL from gatewayUrl\n * 5. Error — \"Run: kb auth login\"\n *\n * KB_REGISTRY_URL decouples the data layer (where the registry lives) from the execution\n * layer (which gateway runs the CLI command). Useful when the registry is behind a different\n * URL than the execution gateway — e.g. closed-loop mirrors or local dev pointing to prod registry.\n *\n * Token auto-refresh: if accessToken is within 60s of expiry, exchanges refreshToken\n * via POST /auth/refresh and overwrites ~/.kb/credentials.json (chmod 600).\n */\n\nimport { readFile, writeFile, chmod } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { homedir } from 'node:os';\nimport { useEnv } from '@kb-labs/sdk';\n\nconst CREDENTIALS_PATH = join(homedir(), '.kb', 'credentials.json');\nconst REGISTRY_GATEWAY_PREFIX = '/api/v1/registry';\nconst FETCH_TIMEOUT_MS = 60_000;\nconst EXPIRY_BUFFER_MS = 60_000;\n\ninterface ResolvedAuth {\n token: string;\n baseUrl: string; // full registry base URL including /api/v1/registry prefix\n handle: string;\n}\n\ninterface StoredCredentials {\n gatewayUrl: string;\n accessToken: string;\n refreshToken: string;\n expiresAt: number;\n handle?: string;\n namespaceId?: string;\n}\n\n/**\n * Resolve registry base URL from env vars only (used when a token is passed explicitly).\n * Priority: KB_REGISTRY_URL → KB_GATEWAY_URL → localhost fallback.\n */\nfunction resolveBaseUrlFromEnv(): string {\n const regUrl = useEnv('KB_REGISTRY_URL');\n const gateway = useEnv('KB_GATEWAY_URL');\n if (regUrl) { return regUrl.replace(/\\/$/, ''); }\n if (gateway) { return `${gateway.replace(/\\/$/, '')}${REGISTRY_GATEWAY_PREFIX}`; }\n return `http://127.0.0.1:4000${REGISTRY_GATEWAY_PREFIX}`;\n}\n\nasync function resolveAuth(): Promise<ResolvedAuth> {\n const envToken = useEnv('KB_REGISTRY_TOKEN');\n const envRegUrl = useEnv('KB_REGISTRY_URL'); // explicit registry base URL (data layer)\n const envGateway = useEnv('KB_GATEWAY_URL'); // legacy: derive registry URL from gateway\n const envHandle = useEnv('KB_REGISTRY_AUTHOR_HANDLE');\n\n // 1. Explicit registry URL + token (CI/CD, closed-loop mirror)\n if (envToken && envRegUrl) {\n return { token: envToken, baseUrl: envRegUrl.replace(/\\/$/, ''), handle: envHandle ?? '' };\n }\n\n // 2. Legacy: token + gateway URL → derive registry base URL\n if (envToken && envGateway) {\n return {\n token: envToken,\n baseUrl: `${envGateway.replace(/\\/$/, '')}${REGISTRY_GATEWAY_PREFIX}`,\n handle: envHandle ?? '',\n };\n }\n\n // 3–4. ~/.kb/credentials.json\n let creds: StoredCredentials;\n try {\n creds = JSON.parse(await readFile(CREDENTIALS_PATH, 'utf-8')) as StoredCredentials;\n } catch {\n throw new Error(\n 'Not authenticated. Run:\\n kb auth login --gateway-url <url> --email <email> --password <password>\\n kb auth register --gateway-url <url> --name <name> --namespace-id <ns>\\n kb auth login --gateway-url <url> --client-id <id> --client-secret <secret>',\n );\n }\n\n // Auto-refresh if token is expired or close to expiry\n if (Date.now() >= creds.expiresAt - EXPIRY_BUFFER_MS) {\n const res = await fetch(`${creds.gatewayUrl}/auth/refresh`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ refreshToken: creds.refreshToken }),\n });\n if (!res.ok) {\n throw new Error('Session expired. Run: kb auth login --gateway-url <url> --client-id <id> --client-secret <secret>');\n }\n const refreshed = await res.json() as { accessToken: string; refreshToken: string; expiresIn: number };\n creds = {\n ...creds,\n accessToken: refreshed.accessToken,\n refreshToken: refreshed.refreshToken,\n expiresAt: Date.now() + refreshed.expiresIn * 1000,\n };\n await writeFile(CREDENTIALS_PATH, JSON.stringify(creds, null, 2), 'utf-8');\n await chmod(CREDENTIALS_PATH, 0o600);\n }\n\n if (!creds.handle) {\n throw new Error(\n 'Author handle not set in credentials. Re-run:\\n kb auth login --gateway-url <url> --client-id <id> --client-secret <secret>',\n );\n }\n\n // 3. credentials + KB_REGISTRY_URL override (execution gateway ≠ registry URL)\n // 4. credentials fully (gatewayUrl used to derive registry base URL)\n const baseUrl = envRegUrl\n ? envRegUrl.replace(/\\/$/, '')\n : `${creds.gatewayUrl.replace(/\\/$/, '')}${REGISTRY_GATEWAY_PREFIX}`;\n\n return { token: creds.accessToken, baseUrl, handle: creds.handle };\n}\n\n/**\n * Resolve the author handle from the credential provider chain.\n * Used when the handle is needed explicitly (e.g. for URL path construction).\n */\nexport async function resolveRegistryHandle(): Promise<string> {\n const auth = await resolveAuth();\n return auth.handle;\n}\n\nexport async function registryPost<T = unknown>(\n path: string,\n body: Record<string, unknown>,\n token?: string,\n): Promise<T> {\n const auth = token\n ? { token, baseUrl: resolveBaseUrlFromEnv() }\n : await resolveAuth();\n\n const url = `${auth.baseUrl}${path}`;\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);\n try {\n const res = await fetch(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${auth.token}` },\n body: JSON.stringify(body),\n signal: controller.signal,\n });\n if (!res.ok) {\n const text = await res.text();\n throw new Error(`Registry ${path} failed (${res.status}): ${text}`);\n }\n if (res.status === 204) { return undefined as T; }\n return await res.json() as T;\n } catch (err) {\n if ((err as Error).name === 'AbortError') {\n throw new Error('Registry request timed out. Is the gateway reachable?');\n }\n throw err;\n } finally {\n clearTimeout(timer);\n }\n}\n\nexport async function registryPostMultipart<T = unknown>(\n path: string,\n tarball: Buffer,\n fields: Record<string, string>,\n token?: string,\n authorHandle?: string,\n): Promise<T> {\n const auth = token\n ? {\n token,\n baseUrl: resolveBaseUrlFromEnv(),\n handle: authorHandle ?? useEnv('KB_REGISTRY_AUTHOR_HANDLE') ?? '',\n }\n : await resolveAuth();\n\n const url = `${auth.baseUrl}${path}`;\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);\n try {\n const form = new FormData();\n form.append('tarball', new Blob([tarball], { type: 'application/octet-stream' }), 'package.tgz');\n for (const [k, v] of Object.entries(fields)) { form.append(k, v); }\n\n const handleHeader: Record<string, string> = auth.handle ? { 'X-Author-Handle': auth.handle } : {};\n\n const res = await fetch(url, {\n method: 'POST',\n headers: { Authorization: `Bearer ${auth.token}`, ...handleHeader },\n body: form,\n signal: controller.signal,\n });\n if (!res.ok) {\n const text = await res.text();\n throw new Error(`Registry publish failed (${res.status}): ${text}`);\n }\n return await res.json() as T;\n } catch (err) {\n if ((err as Error).name === 'AbortError') {\n throw new Error('Registry publish timed out.');\n }\n throw err;\n } finally {\n clearTimeout(timer);\n }\n}\n\nexport async function registryPatch<T = unknown>(\n path: string,\n body: Record<string, unknown>,\n token?: string,\n): Promise<T> {\n const auth = token\n ? { token, baseUrl: resolveBaseUrlFromEnv() }\n : await resolveAuth();\n\n const url = `${auth.baseUrl}${path}`;\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);\n try {\n const res = await fetch(url, {\n method: 'PATCH',\n headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${auth.token}` },\n body: JSON.stringify(body),\n signal: controller.signal,\n });\n if (!res.ok) {\n const text = await res.text();\n throw new Error(`Registry ${path} failed (${res.status}): ${text}`);\n }\n if (res.status === 204) { return undefined as T; }\n return await res.json() as T;\n } catch (err) {\n if ((err as Error).name === 'AbortError') {\n throw new Error('Registry request timed out.');\n }\n throw err;\n } finally {\n clearTimeout(timer);\n }\n}\n","import { defineCommand, handleError, validationError, type CLIInput, type PluginContextV3, type CommandResult } from '@kb-labs/sdk';\nimport { registryPost } from '../registry-http.js';\n\ninterface DeprecateFlags {\n message?: string;\n json?: boolean;\n}\n\nexport default defineCommand<unknown, CLIInput<DeprecateFlags>, unknown>({\n id: 'marketplace:deprecate',\n description: 'Deprecate a package (removed from catalog, install shows warning)',\n\n handler: {\n async execute(ctx: PluginContextV3, input: CLIInput<DeprecateFlags>): Promise<CommandResult> {\n const { flags = {}, argv = [] } = input;\n const pkg = argv[0];\n const t0 = Date.now();\n\n if (!pkg) {\n validationError(ctx, 'Package spec is required', 'Usage: kb marketplace deprecate kb:handle/name [--message \"reason\"]', flags.json);\n return { ok: false, error: 'Package spec is required' };\n }\n\n if (!pkg.startsWith('kb:')) {\n validationError(ctx, 'Package must be a kb: spec', 'Example: kb:kirill/my-plugin', flags.json);\n return { ok: false, error: 'Package must be a kb: spec' };\n }\n\n const sliced = pkg.slice(3);\n const slashIdx = sliced.indexOf('/');\n const handle = slashIdx > 0 ? sliced.slice(0, slashIdx) : '';\n const name = slashIdx > 0 ? sliced.slice(slashIdx + 1) : '';\n if (!handle || !name) {\n validationError(ctx, 'Invalid kb: spec — expected kb:handle/name', undefined, flags.json);\n return { ok: false, error: 'Invalid kb: spec' };\n }\n\n try {\n await registryPost(`/packages/${handle}/${encodeURIComponent(name)}/deprecate`, { message: flags.message });\n\n if (flags.json) {\n ctx.ui?.json?.({ deprecated: true, pkg });\n return { ok: true };\n }\n\n const items = [\n 'Hidden from the marketplace catalog',\n 'Existing installations still work but show a deprecation warning',\n 'New installs are allowed but show a warning',\n ];\n if (flags.message) {\n items.push(`Message: ${flags.message}`);\n }\n\n ctx.ui?.success?.(`${pkg} deprecated`, {\n sections: [{ header: 'What this means', items }],\n hint: 'To block a specific version only, use kb marketplace yank instead',\n timing: Date.now() - t0,\n });\n\n return { ok: true };\n } catch (err) {\n handleError(ctx, err, flags.json);\n return { ok: false, error: err instanceof Error ? err.message : String(err) };\n }\n },\n },\n});\n"]}
|
|
@@ -7,8 +7,15 @@ interface PublishFlags {
|
|
|
7
7
|
metaOnly?: boolean;
|
|
8
8
|
json?: boolean;
|
|
9
9
|
}
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
interface PublishResultData {
|
|
11
|
+
handle: string;
|
|
12
|
+
name: string;
|
|
13
|
+
version: string;
|
|
14
|
+
visibility: string;
|
|
15
|
+
trust: string;
|
|
16
|
+
installCommand: string;
|
|
17
|
+
pageUrl?: string;
|
|
18
|
+
}
|
|
19
|
+
declare const _default: _kb_labs_shared_command_kit.CommandHandlerV3<unknown, CLIInput<PublishFlags>, PublishResultData>;
|
|
13
20
|
|
|
14
21
|
export { _default as default };
|
package/dist/commands/publish.js
CHANGED
|
@@ -151,11 +151,11 @@ var publish_default = defineCommand({
|
|
|
151
151
|
pkgJson = JSON.parse(content);
|
|
152
152
|
} catch {
|
|
153
153
|
validationError(ctx, "Cannot read package.json in current directory", "Run this command from the plugin root directory", flags.json);
|
|
154
|
-
return {
|
|
154
|
+
return { ok: false, error: "Cannot read package.json" };
|
|
155
155
|
}
|
|
156
156
|
if (!pkgJson.name || !pkgJson.version) {
|
|
157
157
|
validationError(ctx, "package.json must have name and version fields", void 0, flags.json);
|
|
158
|
-
return {
|
|
158
|
+
return { ok: false, error: "package.json must have name and version fields" };
|
|
159
159
|
}
|
|
160
160
|
const kb = pkgJson["kb"];
|
|
161
161
|
if (!kb?.manifest && !kb?.adapter) {
|
|
@@ -165,7 +165,7 @@ var publish_default = defineCommand({
|
|
|
165
165
|
"Add a kb.manifest or kb.adapter field to package.json",
|
|
166
166
|
flags.json
|
|
167
167
|
);
|
|
168
|
-
return {
|
|
168
|
+
return { ok: false, error: "Not a KB Labs plugin or adapter" };
|
|
169
169
|
}
|
|
170
170
|
let readme;
|
|
171
171
|
for (const candidate of ["README.md", "README.mdx", "readme.md", "Readme.md"]) {
|
|
@@ -197,10 +197,10 @@ var publish_default = defineCommand({
|
|
|
197
197
|
sections: [{ header: "Package", items: [`${meta.name} @ ${handle}`] }],
|
|
198
198
|
timing: Date.now() - t0
|
|
199
199
|
});
|
|
200
|
-
return {
|
|
200
|
+
return { ok: true };
|
|
201
201
|
} catch (err) {
|
|
202
202
|
handleError(ctx, err, flags.json);
|
|
203
|
-
return {
|
|
203
|
+
return { ok: false, error: err instanceof Error ? err.message : String(err) };
|
|
204
204
|
}
|
|
205
205
|
}
|
|
206
206
|
const primaryKind = kb?.adapter ? "adapter" : "plugin";
|
|
@@ -212,7 +212,7 @@ var publish_default = defineCommand({
|
|
|
212
212
|
packMs = Date.now() - t1;
|
|
213
213
|
} catch (err) {
|
|
214
214
|
handleError(ctx, err, flags.json);
|
|
215
|
-
return {
|
|
215
|
+
return { ok: false, error: err instanceof Error ? err.message : String(err) };
|
|
216
216
|
}
|
|
217
217
|
try {
|
|
218
218
|
const result = await registryPostMultipart(
|
|
@@ -222,7 +222,7 @@ var publish_default = defineCommand({
|
|
|
222
222
|
);
|
|
223
223
|
if (flags.json) {
|
|
224
224
|
ctx.ui?.json?.(result);
|
|
225
|
-
return {
|
|
225
|
+
return { ok: true, result };
|
|
226
226
|
}
|
|
227
227
|
ctx.ui?.chain?.([
|
|
228
228
|
{
|
|
@@ -241,11 +241,11 @@ var publish_default = defineCommand({
|
|
|
241
241
|
timing: Date.now() - t0
|
|
242
242
|
}
|
|
243
243
|
]);
|
|
244
|
-
return {
|
|
244
|
+
return { ok: true, result };
|
|
245
245
|
} catch (err) {
|
|
246
246
|
if (flags.json) {
|
|
247
247
|
handleError(ctx, err, true);
|
|
248
|
-
return {
|
|
248
|
+
return { ok: false, error: err instanceof Error ? err.message : String(err) };
|
|
249
249
|
}
|
|
250
250
|
const message = err instanceof Error ? err.message : String(err);
|
|
251
251
|
ctx.ui?.chain?.([
|
|
@@ -257,7 +257,7 @@ var publish_default = defineCommand({
|
|
|
257
257
|
timing: Date.now() - t0
|
|
258
258
|
}
|
|
259
259
|
]);
|
|
260
|
-
return {
|
|
260
|
+
return { ok: false, error: message };
|
|
261
261
|
}
|
|
262
262
|
}
|
|
263
263
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/registry-http.ts","../../src/pack-plugin.ts","../../src/commands/publish.ts"],"names":["path","fs2"],"mappings":"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","file":"publish.js","sourcesContent":["/**\n * HTTP client for KB Labs Registry service.\n *\n * Credential provider chain (in priority order):\n * 1. KB_REGISTRY_URL + KB_REGISTRY_TOKEN — explicit registry URL (CI/CD, closed-loop mirror)\n * 2. KB_GATEWAY_URL + KB_REGISTRY_TOKEN — legacy CI/CD (derives registry URL from gateway)\n * 3. ~/.kb/credentials.json + KB_REGISTRY_URL — credentials file with explicit registry URL override\n * 4. ~/.kb/credentials.json fully — credentials file, derives registry URL from gatewayUrl\n * 5. Error — \"Run: kb auth login\"\n *\n * KB_REGISTRY_URL decouples the data layer (where the registry lives) from the execution\n * layer (which gateway runs the CLI command). Useful when the registry is behind a different\n * URL than the execution gateway — e.g. closed-loop mirrors or local dev pointing to prod registry.\n *\n * Token auto-refresh: if accessToken is within 60s of expiry, exchanges refreshToken\n * via POST /auth/refresh and overwrites ~/.kb/credentials.json (chmod 600).\n */\n\nimport { readFile, writeFile, chmod } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { homedir } from 'node:os';\nimport { useEnv } from '@kb-labs/sdk';\n\nconst CREDENTIALS_PATH = join(homedir(), '.kb', 'credentials.json');\nconst REGISTRY_GATEWAY_PREFIX = '/api/v1/registry';\nconst FETCH_TIMEOUT_MS = 60_000;\nconst EXPIRY_BUFFER_MS = 60_000;\n\ninterface ResolvedAuth {\n token: string;\n baseUrl: string; // full registry base URL including /api/v1/registry prefix\n handle: string;\n}\n\ninterface StoredCredentials {\n gatewayUrl: string;\n accessToken: string;\n refreshToken: string;\n expiresAt: number;\n handle?: string;\n namespaceId?: string;\n}\n\n/**\n * Resolve registry base URL from env vars only (used when a token is passed explicitly).\n * Priority: KB_REGISTRY_URL → KB_GATEWAY_URL → localhost fallback.\n */\nfunction resolveBaseUrlFromEnv(): string {\n const regUrl = useEnv('KB_REGISTRY_URL');\n const gateway = useEnv('KB_GATEWAY_URL');\n if (regUrl) { return regUrl.replace(/\\/$/, ''); }\n if (gateway) { return `${gateway.replace(/\\/$/, '')}${REGISTRY_GATEWAY_PREFIX}`; }\n return `http://127.0.0.1:4000${REGISTRY_GATEWAY_PREFIX}`;\n}\n\nasync function resolveAuth(): Promise<ResolvedAuth> {\n const envToken = useEnv('KB_REGISTRY_TOKEN');\n const envRegUrl = useEnv('KB_REGISTRY_URL'); // explicit registry base URL (data layer)\n const envGateway = useEnv('KB_GATEWAY_URL'); // legacy: derive registry URL from gateway\n const envHandle = useEnv('KB_REGISTRY_AUTHOR_HANDLE');\n\n // 1. Explicit registry URL + token (CI/CD, closed-loop mirror)\n if (envToken && envRegUrl) {\n return { token: envToken, baseUrl: envRegUrl.replace(/\\/$/, ''), handle: envHandle ?? '' };\n }\n\n // 2. Legacy: token + gateway URL → derive registry base URL\n if (envToken && envGateway) {\n return {\n token: envToken,\n baseUrl: `${envGateway.replace(/\\/$/, '')}${REGISTRY_GATEWAY_PREFIX}`,\n handle: envHandle ?? '',\n };\n }\n\n // 3–4. ~/.kb/credentials.json\n let creds: StoredCredentials;\n try {\n creds = JSON.parse(await readFile(CREDENTIALS_PATH, 'utf-8')) as StoredCredentials;\n } catch {\n throw new Error(\n 'Not authenticated. Run:\\n kb auth login --gateway-url <url> --email <email> --password <password>\\n kb auth register --gateway-url <url> --name <name> --namespace-id <ns>\\n kb auth login --gateway-url <url> --client-id <id> --client-secret <secret>',\n );\n }\n\n // Auto-refresh if token is expired or close to expiry\n if (Date.now() >= creds.expiresAt - EXPIRY_BUFFER_MS) {\n const res = await fetch(`${creds.gatewayUrl}/auth/refresh`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ refreshToken: creds.refreshToken }),\n });\n if (!res.ok) {\n throw new Error('Session expired. Run: kb auth login --gateway-url <url> --client-id <id> --client-secret <secret>');\n }\n const refreshed = await res.json() as { accessToken: string; refreshToken: string; expiresIn: number };\n creds = {\n ...creds,\n accessToken: refreshed.accessToken,\n refreshToken: refreshed.refreshToken,\n expiresAt: Date.now() + refreshed.expiresIn * 1000,\n };\n await writeFile(CREDENTIALS_PATH, JSON.stringify(creds, null, 2), 'utf-8');\n await chmod(CREDENTIALS_PATH, 0o600);\n }\n\n if (!creds.handle) {\n throw new Error(\n 'Author handle not set in credentials. Re-run:\\n kb auth login --gateway-url <url> --client-id <id> --client-secret <secret>',\n );\n }\n\n // 3. credentials + KB_REGISTRY_URL override (execution gateway ≠ registry URL)\n // 4. credentials fully (gatewayUrl used to derive registry base URL)\n const baseUrl = envRegUrl\n ? envRegUrl.replace(/\\/$/, '')\n : `${creds.gatewayUrl.replace(/\\/$/, '')}${REGISTRY_GATEWAY_PREFIX}`;\n\n return { token: creds.accessToken, baseUrl, handle: creds.handle };\n}\n\n/**\n * Resolve the author handle from the credential provider chain.\n * Used when the handle is needed explicitly (e.g. for URL path construction).\n */\nexport async function resolveRegistryHandle(): Promise<string> {\n const auth = await resolveAuth();\n return auth.handle;\n}\n\nexport async function registryPost<T = unknown>(\n path: string,\n body: Record<string, unknown>,\n token?: string,\n): Promise<T> {\n const auth = token\n ? { token, baseUrl: resolveBaseUrlFromEnv() }\n : await resolveAuth();\n\n const url = `${auth.baseUrl}${path}`;\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);\n try {\n const res = await fetch(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${auth.token}` },\n body: JSON.stringify(body),\n signal: controller.signal,\n });\n if (!res.ok) {\n const text = await res.text();\n throw new Error(`Registry ${path} failed (${res.status}): ${text}`);\n }\n if (res.status === 204) { return undefined as T; }\n return await res.json() as T;\n } catch (err) {\n if ((err as Error).name === 'AbortError') {\n throw new Error('Registry request timed out. Is the gateway reachable?');\n }\n throw err;\n } finally {\n clearTimeout(timer);\n }\n}\n\nexport async function registryPostMultipart<T = unknown>(\n path: string,\n tarball: Buffer,\n fields: Record<string, string>,\n token?: string,\n authorHandle?: string,\n): Promise<T> {\n const auth = token\n ? {\n token,\n baseUrl: resolveBaseUrlFromEnv(),\n handle: authorHandle ?? useEnv('KB_REGISTRY_AUTHOR_HANDLE') ?? '',\n }\n : await resolveAuth();\n\n const url = `${auth.baseUrl}${path}`;\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);\n try {\n const form = new FormData();\n form.append('tarball', new Blob([tarball], { type: 'application/octet-stream' }), 'package.tgz');\n for (const [k, v] of Object.entries(fields)) { form.append(k, v); }\n\n const handleHeader: Record<string, string> = auth.handle ? { 'X-Author-Handle': auth.handle } : {};\n\n const res = await fetch(url, {\n method: 'POST',\n headers: { Authorization: `Bearer ${auth.token}`, ...handleHeader },\n body: form,\n signal: controller.signal,\n });\n if (!res.ok) {\n const text = await res.text();\n throw new Error(`Registry publish failed (${res.status}): ${text}`);\n }\n return await res.json() as T;\n } catch (err) {\n if ((err as Error).name === 'AbortError') {\n throw new Error('Registry publish timed out.');\n }\n throw err;\n } finally {\n clearTimeout(timer);\n }\n}\n\nexport async function registryPatch<T = unknown>(\n path: string,\n body: Record<string, unknown>,\n token?: string,\n): Promise<T> {\n const auth = token\n ? { token, baseUrl: resolveBaseUrlFromEnv() }\n : await resolveAuth();\n\n const url = `${auth.baseUrl}${path}`;\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);\n try {\n const res = await fetch(url, {\n method: 'PATCH',\n headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${auth.token}` },\n body: JSON.stringify(body),\n signal: controller.signal,\n });\n if (!res.ok) {\n const text = await res.text();\n throw new Error(`Registry ${path} failed (${res.status}): ${text}`);\n }\n if (res.status === 204) { return undefined as T; }\n return await res.json() as T;\n } catch (err) {\n if ((err as Error).name === 'AbortError') {\n throw new Error('Registry request timed out.');\n }\n throw err;\n } finally {\n clearTimeout(timer);\n }\n}\n","import * as fs from 'node:fs/promises';\nimport { execa } from 'execa';\n\n/** Runs `pnpm pack` in the given directory and returns the tarball buffer. */\nexport async function packPlugin(dir: string): Promise<Buffer> {\n const { stdout } = await execa('pnpm', ['pack', '--pack-destination', '/tmp'], { cwd: dir });\n const tarballPath = stdout.trim().split('\\n').at(-1)!.trim();\n const tarball = await fs.readFile(tarballPath);\n await fs.unlink(tarballPath).catch(() => { /* ignore cleanup failure */ });\n return tarball;\n}\n","import * as path from 'node:path';\nimport * as fs from 'node:fs/promises';\nimport { defineCommand, handleError, validationError, type CLIInput, type PluginContextV3 } from '@kb-labs/sdk';\nimport { registryPostMultipart, registryPatch, resolveRegistryHandle } from '../registry-http.js';\nimport { packPlugin } from '../pack-plugin.js';\n\ninterface PublishFlags {\n private?: boolean;\n path?: string;\n metaOnly?: boolean;\n json?: boolean;\n}\n\ninterface PublishResultData {\n handle: string;\n name: string;\n version: string;\n visibility: string;\n trust: string;\n installCommand: string;\n pageUrl?: string;\n}\n\nexport default defineCommand<unknown, CLIInput<PublishFlags>, { exitCode: number }>({\n id: 'marketplace:publish',\n description: 'Publish plugin to KB Labs Registry',\n\n handler: {\n async execute(ctx: PluginContextV3, input: CLIInput<PublishFlags>): Promise<{ exitCode: number }> {\n const { flags = {} } = input;\n const pluginDir = path.resolve(ctx.cwd, flags.path ?? '.');\n const visibility = flags.private ? 'private' : 'public';\n const t0 = Date.now();\n\n let pkgJson: Record<string, unknown>;\n try {\n const content = await fs.readFile(path.join(pluginDir, 'package.json'), 'utf-8');\n pkgJson = JSON.parse(content) as Record<string, unknown>;\n } catch {\n validationError(ctx, 'Cannot read package.json in current directory', 'Run this command from the plugin root directory', flags.json);\n return { exitCode: 1 };\n }\n\n if (!pkgJson.name || !pkgJson.version) {\n validationError(ctx, 'package.json must have name and version fields', undefined, flags.json);\n return { exitCode: 1 };\n }\n\n const kb = pkgJson['kb'] as Record<string, unknown> | undefined;\n if (!kb?.manifest && !kb?.adapter) {\n validationError(\n ctx,\n 'Not a KB Labs plugin or adapter',\n 'Add a kb.manifest or kb.adapter field to package.json',\n flags.json,\n );\n return { exitCode: 1 };\n }\n\n // Read README (non-fatal)\n let readme: string | undefined;\n for (const candidate of ['README.md', 'README.mdx', 'readme.md', 'Readme.md']) {\n readme = await fs.readFile(path.join(pluginDir, candidate), 'utf-8').catch(() => undefined);\n if (readme) break;\n }\n\n // Extract manifest fields for the detail page\n const manifest = (kb?.manifest ?? {}) as Record<string, unknown>;\n const manifestCommands = Array.isArray(manifest['commands'])\n ? (manifest['commands'] as Array<{ id?: string; name?: string }>).map(c => c.id ?? c.name ?? '').filter(Boolean)\n : undefined;\n\n const meta = {\n name: pkgJson.name as string,\n version: pkgJson.version as string,\n description: pkgJson.description as string | undefined,\n author: pkgJson.author as unknown,\n repository: pkgJson.repository as unknown,\n keywords: pkgJson.keywords as string[] | undefined,\n license: pkgJson.license as string | undefined,\n homepage: pkgJson.homepage as string | undefined,\n readme,\n permissions: manifest['permissions'] as string[] | undefined,\n envVars: manifest['envVars'] as string[] | undefined,\n allowedHosts: manifest['allowedHosts'] as string[] | undefined,\n commands: manifestCommands,\n };\n\n if (flags.metaOnly) {\n try {\n const handle = await resolveRegistryHandle();\n await registryPatch(`/packages/${handle}/${meta.name}/meta`, meta);\n ctx.ui?.success?.('Metadata updated', {\n sections: [{ header: 'Package', items: [`${meta.name} @ ${handle}`] }],\n timing: Date.now() - t0,\n });\n return { exitCode: 0 };\n } catch (err) {\n handleError(ctx, err, flags.json);\n return { exitCode: 1 };\n }\n }\n\n const primaryKind = kb?.adapter ? 'adapter' : 'plugin';\n\n const t1 = Date.now();\n let tarball: Buffer;\n let packMs: number;\n try {\n tarball = await packPlugin(pluginDir);\n packMs = Date.now() - t1;\n } catch (err) {\n handleError(ctx, err, flags.json);\n return { exitCode: 1 };\n }\n\n try {\n const result = await registryPostMultipart<PublishResultData>(\n '/packages/publish',\n tarball,\n { meta: JSON.stringify({ meta, visibility, primaryKind }) },\n );\n\n if (flags.json) {\n ctx.ui?.json?.(result);\n return { exitCode: 0 };\n }\n\n ctx.ui?.chain?.([\n {\n title: `Packed ${meta.name}@${meta.version}`,\n timing: packMs,\n },\n {\n title: `${result.name}@${result.version} published`,\n status: 'success',\n summary: {\n 'Visibility': result.visibility,\n 'Trust': result.trust === 'trusted' ? 'KB Labs Platform ✓' : 'community',\n ...(result.pageUrl ? { 'Page': result.pageUrl } : {}),\n },\n sections: [{ header: 'Install', items: [{ text: result.installCommand, truncate: 500 }] }],\n timing: Date.now() - t0,\n },\n ]);\n\n return { exitCode: 0 };\n } catch (err) {\n if (flags.json) {\n handleError(ctx, err, true);\n return { exitCode: 1 };\n }\n const message = err instanceof Error ? err.message : String(err);\n ctx.ui?.chain?.([\n { title: `Packed ${meta.name}@${meta.version}`, timing: packMs },\n {\n title: 'Publish failed',\n status: 'error',\n sections: [{ items: [message] }],\n timing: Date.now() - t0,\n },\n ]);\n return { exitCode: 1 };\n }\n },\n },\n});\n\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/registry-http.ts","../../src/pack-plugin.ts","../../src/commands/publish.ts"],"names":["path","fs2"],"mappings":"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","file":"publish.js","sourcesContent":["/**\n * HTTP client for KB Labs Registry service.\n *\n * Credential provider chain (in priority order):\n * 1. KB_REGISTRY_URL + KB_REGISTRY_TOKEN — explicit registry URL (CI/CD, closed-loop mirror)\n * 2. KB_GATEWAY_URL + KB_REGISTRY_TOKEN — legacy CI/CD (derives registry URL from gateway)\n * 3. ~/.kb/credentials.json + KB_REGISTRY_URL — credentials file with explicit registry URL override\n * 4. ~/.kb/credentials.json fully — credentials file, derives registry URL from gatewayUrl\n * 5. Error — \"Run: kb auth login\"\n *\n * KB_REGISTRY_URL decouples the data layer (where the registry lives) from the execution\n * layer (which gateway runs the CLI command). Useful when the registry is behind a different\n * URL than the execution gateway — e.g. closed-loop mirrors or local dev pointing to prod registry.\n *\n * Token auto-refresh: if accessToken is within 60s of expiry, exchanges refreshToken\n * via POST /auth/refresh and overwrites ~/.kb/credentials.json (chmod 600).\n */\n\nimport { readFile, writeFile, chmod } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { homedir } from 'node:os';\nimport { useEnv } from '@kb-labs/sdk';\n\nconst CREDENTIALS_PATH = join(homedir(), '.kb', 'credentials.json');\nconst REGISTRY_GATEWAY_PREFIX = '/api/v1/registry';\nconst FETCH_TIMEOUT_MS = 60_000;\nconst EXPIRY_BUFFER_MS = 60_000;\n\ninterface ResolvedAuth {\n token: string;\n baseUrl: string; // full registry base URL including /api/v1/registry prefix\n handle: string;\n}\n\ninterface StoredCredentials {\n gatewayUrl: string;\n accessToken: string;\n refreshToken: string;\n expiresAt: number;\n handle?: string;\n namespaceId?: string;\n}\n\n/**\n * Resolve registry base URL from env vars only (used when a token is passed explicitly).\n * Priority: KB_REGISTRY_URL → KB_GATEWAY_URL → localhost fallback.\n */\nfunction resolveBaseUrlFromEnv(): string {\n const regUrl = useEnv('KB_REGISTRY_URL');\n const gateway = useEnv('KB_GATEWAY_URL');\n if (regUrl) { return regUrl.replace(/\\/$/, ''); }\n if (gateway) { return `${gateway.replace(/\\/$/, '')}${REGISTRY_GATEWAY_PREFIX}`; }\n return `http://127.0.0.1:4000${REGISTRY_GATEWAY_PREFIX}`;\n}\n\nasync function resolveAuth(): Promise<ResolvedAuth> {\n const envToken = useEnv('KB_REGISTRY_TOKEN');\n const envRegUrl = useEnv('KB_REGISTRY_URL'); // explicit registry base URL (data layer)\n const envGateway = useEnv('KB_GATEWAY_URL'); // legacy: derive registry URL from gateway\n const envHandle = useEnv('KB_REGISTRY_AUTHOR_HANDLE');\n\n // 1. Explicit registry URL + token (CI/CD, closed-loop mirror)\n if (envToken && envRegUrl) {\n return { token: envToken, baseUrl: envRegUrl.replace(/\\/$/, ''), handle: envHandle ?? '' };\n }\n\n // 2. Legacy: token + gateway URL → derive registry base URL\n if (envToken && envGateway) {\n return {\n token: envToken,\n baseUrl: `${envGateway.replace(/\\/$/, '')}${REGISTRY_GATEWAY_PREFIX}`,\n handle: envHandle ?? '',\n };\n }\n\n // 3–4. ~/.kb/credentials.json\n let creds: StoredCredentials;\n try {\n creds = JSON.parse(await readFile(CREDENTIALS_PATH, 'utf-8')) as StoredCredentials;\n } catch {\n throw new Error(\n 'Not authenticated. Run:\\n kb auth login --gateway-url <url> --email <email> --password <password>\\n kb auth register --gateway-url <url> --name <name> --namespace-id <ns>\\n kb auth login --gateway-url <url> --client-id <id> --client-secret <secret>',\n );\n }\n\n // Auto-refresh if token is expired or close to expiry\n if (Date.now() >= creds.expiresAt - EXPIRY_BUFFER_MS) {\n const res = await fetch(`${creds.gatewayUrl}/auth/refresh`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ refreshToken: creds.refreshToken }),\n });\n if (!res.ok) {\n throw new Error('Session expired. Run: kb auth login --gateway-url <url> --client-id <id> --client-secret <secret>');\n }\n const refreshed = await res.json() as { accessToken: string; refreshToken: string; expiresIn: number };\n creds = {\n ...creds,\n accessToken: refreshed.accessToken,\n refreshToken: refreshed.refreshToken,\n expiresAt: Date.now() + refreshed.expiresIn * 1000,\n };\n await writeFile(CREDENTIALS_PATH, JSON.stringify(creds, null, 2), 'utf-8');\n await chmod(CREDENTIALS_PATH, 0o600);\n }\n\n if (!creds.handle) {\n throw new Error(\n 'Author handle not set in credentials. Re-run:\\n kb auth login --gateway-url <url> --client-id <id> --client-secret <secret>',\n );\n }\n\n // 3. credentials + KB_REGISTRY_URL override (execution gateway ≠ registry URL)\n // 4. credentials fully (gatewayUrl used to derive registry base URL)\n const baseUrl = envRegUrl\n ? envRegUrl.replace(/\\/$/, '')\n : `${creds.gatewayUrl.replace(/\\/$/, '')}${REGISTRY_GATEWAY_PREFIX}`;\n\n return { token: creds.accessToken, baseUrl, handle: creds.handle };\n}\n\n/**\n * Resolve the author handle from the credential provider chain.\n * Used when the handle is needed explicitly (e.g. for URL path construction).\n */\nexport async function resolveRegistryHandle(): Promise<string> {\n const auth = await resolveAuth();\n return auth.handle;\n}\n\nexport async function registryPost<T = unknown>(\n path: string,\n body: Record<string, unknown>,\n token?: string,\n): Promise<T> {\n const auth = token\n ? { token, baseUrl: resolveBaseUrlFromEnv() }\n : await resolveAuth();\n\n const url = `${auth.baseUrl}${path}`;\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);\n try {\n const res = await fetch(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${auth.token}` },\n body: JSON.stringify(body),\n signal: controller.signal,\n });\n if (!res.ok) {\n const text = await res.text();\n throw new Error(`Registry ${path} failed (${res.status}): ${text}`);\n }\n if (res.status === 204) { return undefined as T; }\n return await res.json() as T;\n } catch (err) {\n if ((err as Error).name === 'AbortError') {\n throw new Error('Registry request timed out. Is the gateway reachable?');\n }\n throw err;\n } finally {\n clearTimeout(timer);\n }\n}\n\nexport async function registryPostMultipart<T = unknown>(\n path: string,\n tarball: Buffer,\n fields: Record<string, string>,\n token?: string,\n authorHandle?: string,\n): Promise<T> {\n const auth = token\n ? {\n token,\n baseUrl: resolveBaseUrlFromEnv(),\n handle: authorHandle ?? useEnv('KB_REGISTRY_AUTHOR_HANDLE') ?? '',\n }\n : await resolveAuth();\n\n const url = `${auth.baseUrl}${path}`;\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);\n try {\n const form = new FormData();\n form.append('tarball', new Blob([tarball], { type: 'application/octet-stream' }), 'package.tgz');\n for (const [k, v] of Object.entries(fields)) { form.append(k, v); }\n\n const handleHeader: Record<string, string> = auth.handle ? { 'X-Author-Handle': auth.handle } : {};\n\n const res = await fetch(url, {\n method: 'POST',\n headers: { Authorization: `Bearer ${auth.token}`, ...handleHeader },\n body: form,\n signal: controller.signal,\n });\n if (!res.ok) {\n const text = await res.text();\n throw new Error(`Registry publish failed (${res.status}): ${text}`);\n }\n return await res.json() as T;\n } catch (err) {\n if ((err as Error).name === 'AbortError') {\n throw new Error('Registry publish timed out.');\n }\n throw err;\n } finally {\n clearTimeout(timer);\n }\n}\n\nexport async function registryPatch<T = unknown>(\n path: string,\n body: Record<string, unknown>,\n token?: string,\n): Promise<T> {\n const auth = token\n ? { token, baseUrl: resolveBaseUrlFromEnv() }\n : await resolveAuth();\n\n const url = `${auth.baseUrl}${path}`;\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);\n try {\n const res = await fetch(url, {\n method: 'PATCH',\n headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${auth.token}` },\n body: JSON.stringify(body),\n signal: controller.signal,\n });\n if (!res.ok) {\n const text = await res.text();\n throw new Error(`Registry ${path} failed (${res.status}): ${text}`);\n }\n if (res.status === 204) { return undefined as T; }\n return await res.json() as T;\n } catch (err) {\n if ((err as Error).name === 'AbortError') {\n throw new Error('Registry request timed out.');\n }\n throw err;\n } finally {\n clearTimeout(timer);\n }\n}\n","import * as fs from 'node:fs/promises';\nimport { execa } from 'execa';\n\n/** Runs `pnpm pack` in the given directory and returns the tarball buffer. */\nexport async function packPlugin(dir: string): Promise<Buffer> {\n const { stdout } = await execa('pnpm', ['pack', '--pack-destination', '/tmp'], { cwd: dir });\n const tarballPath = stdout.trim().split('\\n').at(-1)!.trim();\n const tarball = await fs.readFile(tarballPath);\n await fs.unlink(tarballPath).catch(() => { /* ignore cleanup failure */ });\n return tarball;\n}\n","import * as path from 'node:path';\nimport * as fs from 'node:fs/promises';\nimport { defineCommand, handleError, validationError, type CLIInput, type PluginContextV3, type CommandResult } from '@kb-labs/sdk';\nimport { registryPostMultipart, registryPatch, resolveRegistryHandle } from '../registry-http.js';\nimport { packPlugin } from '../pack-plugin.js';\n\ninterface PublishFlags {\n private?: boolean;\n path?: string;\n metaOnly?: boolean;\n json?: boolean;\n}\n\ninterface PublishResultData {\n handle: string;\n name: string;\n version: string;\n visibility: string;\n trust: string;\n installCommand: string;\n pageUrl?: string;\n}\n\nexport default defineCommand<unknown, CLIInput<PublishFlags>, PublishResultData>({\n id: 'marketplace:publish',\n description: 'Publish plugin to KB Labs Registry',\n\n handler: {\n async execute(ctx: PluginContextV3, input: CLIInput<PublishFlags>): Promise<CommandResult<PublishResultData>> {\n const { flags = {} } = input;\n const pluginDir = path.resolve(ctx.cwd, flags.path ?? '.');\n const visibility = flags.private ? 'private' : 'public';\n const t0 = Date.now();\n\n let pkgJson: Record<string, unknown>;\n try {\n const content = await fs.readFile(path.join(pluginDir, 'package.json'), 'utf-8');\n pkgJson = JSON.parse(content) as Record<string, unknown>;\n } catch {\n validationError(ctx, 'Cannot read package.json in current directory', 'Run this command from the plugin root directory', flags.json);\n return { ok: false, error: 'Cannot read package.json' };\n }\n\n if (!pkgJson.name || !pkgJson.version) {\n validationError(ctx, 'package.json must have name and version fields', undefined, flags.json);\n return { ok: false, error: 'package.json must have name and version fields' };\n }\n\n const kb = pkgJson['kb'] as Record<string, unknown> | undefined;\n if (!kb?.manifest && !kb?.adapter) {\n validationError(\n ctx,\n 'Not a KB Labs plugin or adapter',\n 'Add a kb.manifest or kb.adapter field to package.json',\n flags.json,\n );\n return { ok: false, error: 'Not a KB Labs plugin or adapter' };\n }\n\n // Read README (non-fatal)\n let readme: string | undefined;\n for (const candidate of ['README.md', 'README.mdx', 'readme.md', 'Readme.md']) {\n readme = await fs.readFile(path.join(pluginDir, candidate), 'utf-8').catch(() => undefined);\n if (readme) break;\n }\n\n // Extract manifest fields for the detail page\n const manifest = (kb?.manifest ?? {}) as Record<string, unknown>;\n const manifestCommands = Array.isArray(manifest['commands'])\n ? (manifest['commands'] as Array<{ id?: string; name?: string }>).map(c => c.id ?? c.name ?? '').filter(Boolean)\n : undefined;\n\n const meta = {\n name: pkgJson.name as string,\n version: pkgJson.version as string,\n description: pkgJson.description as string | undefined,\n author: pkgJson.author as unknown,\n repository: pkgJson.repository as unknown,\n keywords: pkgJson.keywords as string[] | undefined,\n license: pkgJson.license as string | undefined,\n homepage: pkgJson.homepage as string | undefined,\n readme,\n permissions: manifest['permissions'] as string[] | undefined,\n envVars: manifest['envVars'] as string[] | undefined,\n allowedHosts: manifest['allowedHosts'] as string[] | undefined,\n commands: manifestCommands,\n };\n\n if (flags.metaOnly) {\n try {\n const handle = await resolveRegistryHandle();\n await registryPatch(`/packages/${handle}/${meta.name}/meta`, meta);\n ctx.ui?.success?.('Metadata updated', {\n sections: [{ header: 'Package', items: [`${meta.name} @ ${handle}`] }],\n timing: Date.now() - t0,\n });\n return { ok: true };\n } catch (err) {\n handleError(ctx, err, flags.json);\n return { ok: false, error: err instanceof Error ? err.message : String(err) };\n }\n }\n\n const primaryKind = kb?.adapter ? 'adapter' : 'plugin';\n\n const t1 = Date.now();\n let tarball: Buffer;\n let packMs: number;\n try {\n tarball = await packPlugin(pluginDir);\n packMs = Date.now() - t1;\n } catch (err) {\n handleError(ctx, err, flags.json);\n return { ok: false, error: err instanceof Error ? err.message : String(err) };\n }\n\n try {\n const result = await registryPostMultipart<PublishResultData>(\n '/packages/publish',\n tarball,\n { meta: JSON.stringify({ meta, visibility, primaryKind }) },\n );\n\n if (flags.json) {\n ctx.ui?.json?.(result);\n return { ok: true, result };\n }\n\n ctx.ui?.chain?.([\n {\n title: `Packed ${meta.name}@${meta.version}`,\n timing: packMs,\n },\n {\n title: `${result.name}@${result.version} published`,\n status: 'success',\n summary: {\n 'Visibility': result.visibility,\n 'Trust': result.trust === 'trusted' ? 'KB Labs Platform ✓' : 'community',\n ...(result.pageUrl ? { 'Page': result.pageUrl } : {}),\n },\n sections: [{ header: 'Install', items: [{ text: result.installCommand, truncate: 500 }] }],\n timing: Date.now() - t0,\n },\n ]);\n\n return { ok: true, result };\n } catch (err) {\n if (flags.json) {\n handleError(ctx, err, true);\n return { ok: false, error: err instanceof Error ? err.message : String(err) };\n }\n const message = err instanceof Error ? err.message : String(err);\n ctx.ui?.chain?.([\n { title: `Packed ${meta.name}@${meta.version}`, timing: packMs },\n {\n title: 'Publish failed',\n status: 'error',\n sections: [{ items: [message] }],\n timing: Date.now() - t0,\n },\n ]);\n return { ok: false, error: message };\n }\n },\n },\n});\n"]}
|
package/dist/commands/share.d.ts
CHANGED
|
@@ -7,8 +7,11 @@ interface ShareFlags {
|
|
|
7
7
|
ttl?: string;
|
|
8
8
|
json?: boolean;
|
|
9
9
|
}
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
interface ShareTokenResult {
|
|
11
|
+
token?: string;
|
|
12
|
+
pkg?: string;
|
|
13
|
+
expiresAt?: string;
|
|
14
|
+
}
|
|
15
|
+
declare const _default: _kb_labs_shared_command_kit.CommandHandlerV3<unknown, CLIInput<ShareFlags>, ShareTokenResult>;
|
|
13
16
|
|
|
14
17
|
export { _default as default };
|
package/dist/commands/share.js
CHANGED
|
@@ -99,15 +99,15 @@ var share_default = defineCommand({
|
|
|
99
99
|
const t0 = Date.now();
|
|
100
100
|
if (!pkg) {
|
|
101
101
|
validationError(ctx, "Package spec is required", "Usage: kb marketplace share kb:handle/name [--with handle | --link]", flags.json);
|
|
102
|
-
return {
|
|
102
|
+
return { ok: false, error: "Package spec is required" };
|
|
103
103
|
}
|
|
104
104
|
if (!flags.with && !flags.link) {
|
|
105
105
|
validationError(ctx, "Specify --with <handle> to grant access, or --link to generate a share token", void 0, flags.json);
|
|
106
|
-
return {
|
|
106
|
+
return { ok: false, error: "Specify --with or --link" };
|
|
107
107
|
}
|
|
108
108
|
if (!pkg.startsWith("kb:")) {
|
|
109
109
|
validationError(ctx, "Package must be a kb: spec", "Example: kb:kirill/my-plugin", flags.json);
|
|
110
|
-
return {
|
|
110
|
+
return { ok: false, error: "Package must be a kb: spec" };
|
|
111
111
|
}
|
|
112
112
|
const sliced = pkg.slice(3);
|
|
113
113
|
const slashIdx = sliced.indexOf("/");
|
|
@@ -115,14 +115,14 @@ var share_default = defineCommand({
|
|
|
115
115
|
const name = slashIdx > 0 ? sliced.slice(slashIdx + 1) : "";
|
|
116
116
|
if (!handle || !name) {
|
|
117
117
|
validationError(ctx, "Invalid kb: spec \u2014 expected kb:handle/name", void 0, flags.json);
|
|
118
|
-
return {
|
|
118
|
+
return { ok: false, error: "Invalid kb: spec" };
|
|
119
119
|
}
|
|
120
120
|
try {
|
|
121
121
|
if (flags.with) {
|
|
122
122
|
await registryPost(`/packages/${handle}/${encodeURIComponent(name)}/share/allowlist`, { namespaceId: flags.with });
|
|
123
123
|
if (flags.json) {
|
|
124
124
|
ctx.ui?.json?.({ added: flags.with, pkg });
|
|
125
|
-
return {
|
|
125
|
+
return { ok: true };
|
|
126
126
|
}
|
|
127
127
|
ctx.ui?.success?.(`${flags.with} can now install ${pkg}`, {
|
|
128
128
|
sections: [
|
|
@@ -134,13 +134,13 @@ var share_default = defineCommand({
|
|
|
134
134
|
hint: "For one-time access without an account, use --link instead",
|
|
135
135
|
timing: Date.now() - t0
|
|
136
136
|
});
|
|
137
|
-
return {
|
|
137
|
+
return { ok: true };
|
|
138
138
|
}
|
|
139
139
|
const ttlDays = flags.ttl ? parseInt(flags.ttl, 10) : 7;
|
|
140
140
|
const result = await registryPost(`/packages/${handle}/${encodeURIComponent(name)}/share/token`, { ttlDays });
|
|
141
141
|
if (flags.json) {
|
|
142
142
|
ctx.ui?.json?.(result);
|
|
143
|
-
return {
|
|
143
|
+
return { ok: true, result };
|
|
144
144
|
}
|
|
145
145
|
const expiry = result.expiresAt ? new Date(result.expiresAt).toLocaleDateString() : `${ttlDays} days`;
|
|
146
146
|
ctx.ui?.success?.("Share link created", {
|
|
@@ -155,10 +155,10 @@ var share_default = defineCommand({
|
|
|
155
155
|
}],
|
|
156
156
|
timing: Date.now() - t0
|
|
157
157
|
});
|
|
158
|
-
return {
|
|
158
|
+
return { ok: true, result };
|
|
159
159
|
} catch (err) {
|
|
160
160
|
handleError(ctx, err, flags.json);
|
|
161
|
-
return {
|
|
161
|
+
return { ok: false, error: err instanceof Error ? err.message : String(err) };
|
|
162
162
|
}
|
|
163
163
|
}
|
|
164
164
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/registry-http.ts","../../src/commands/share.ts"],"names":[],"mappings":"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","file":"share.js","sourcesContent":["/**\n * HTTP client for KB Labs Registry service.\n *\n * Credential provider chain (in priority order):\n * 1. KB_REGISTRY_URL + KB_REGISTRY_TOKEN — explicit registry URL (CI/CD, closed-loop mirror)\n * 2. KB_GATEWAY_URL + KB_REGISTRY_TOKEN — legacy CI/CD (derives registry URL from gateway)\n * 3. ~/.kb/credentials.json + KB_REGISTRY_URL — credentials file with explicit registry URL override\n * 4. ~/.kb/credentials.json fully — credentials file, derives registry URL from gatewayUrl\n * 5. Error — \"Run: kb auth login\"\n *\n * KB_REGISTRY_URL decouples the data layer (where the registry lives) from the execution\n * layer (which gateway runs the CLI command). Useful when the registry is behind a different\n * URL than the execution gateway — e.g. closed-loop mirrors or local dev pointing to prod registry.\n *\n * Token auto-refresh: if accessToken is within 60s of expiry, exchanges refreshToken\n * via POST /auth/refresh and overwrites ~/.kb/credentials.json (chmod 600).\n */\n\nimport { readFile, writeFile, chmod } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { homedir } from 'node:os';\nimport { useEnv } from '@kb-labs/sdk';\n\nconst CREDENTIALS_PATH = join(homedir(), '.kb', 'credentials.json');\nconst REGISTRY_GATEWAY_PREFIX = '/api/v1/registry';\nconst FETCH_TIMEOUT_MS = 60_000;\nconst EXPIRY_BUFFER_MS = 60_000;\n\ninterface ResolvedAuth {\n token: string;\n baseUrl: string; // full registry base URL including /api/v1/registry prefix\n handle: string;\n}\n\ninterface StoredCredentials {\n gatewayUrl: string;\n accessToken: string;\n refreshToken: string;\n expiresAt: number;\n handle?: string;\n namespaceId?: string;\n}\n\n/**\n * Resolve registry base URL from env vars only (used when a token is passed explicitly).\n * Priority: KB_REGISTRY_URL → KB_GATEWAY_URL → localhost fallback.\n */\nfunction resolveBaseUrlFromEnv(): string {\n const regUrl = useEnv('KB_REGISTRY_URL');\n const gateway = useEnv('KB_GATEWAY_URL');\n if (regUrl) { return regUrl.replace(/\\/$/, ''); }\n if (gateway) { return `${gateway.replace(/\\/$/, '')}${REGISTRY_GATEWAY_PREFIX}`; }\n return `http://127.0.0.1:4000${REGISTRY_GATEWAY_PREFIX}`;\n}\n\nasync function resolveAuth(): Promise<ResolvedAuth> {\n const envToken = useEnv('KB_REGISTRY_TOKEN');\n const envRegUrl = useEnv('KB_REGISTRY_URL'); // explicit registry base URL (data layer)\n const envGateway = useEnv('KB_GATEWAY_URL'); // legacy: derive registry URL from gateway\n const envHandle = useEnv('KB_REGISTRY_AUTHOR_HANDLE');\n\n // 1. Explicit registry URL + token (CI/CD, closed-loop mirror)\n if (envToken && envRegUrl) {\n return { token: envToken, baseUrl: envRegUrl.replace(/\\/$/, ''), handle: envHandle ?? '' };\n }\n\n // 2. Legacy: token + gateway URL → derive registry base URL\n if (envToken && envGateway) {\n return {\n token: envToken,\n baseUrl: `${envGateway.replace(/\\/$/, '')}${REGISTRY_GATEWAY_PREFIX}`,\n handle: envHandle ?? '',\n };\n }\n\n // 3–4. ~/.kb/credentials.json\n let creds: StoredCredentials;\n try {\n creds = JSON.parse(await readFile(CREDENTIALS_PATH, 'utf-8')) as StoredCredentials;\n } catch {\n throw new Error(\n 'Not authenticated. Run:\\n kb auth login --gateway-url <url> --email <email> --password <password>\\n kb auth register --gateway-url <url> --name <name> --namespace-id <ns>\\n kb auth login --gateway-url <url> --client-id <id> --client-secret <secret>',\n );\n }\n\n // Auto-refresh if token is expired or close to expiry\n if (Date.now() >= creds.expiresAt - EXPIRY_BUFFER_MS) {\n const res = await fetch(`${creds.gatewayUrl}/auth/refresh`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ refreshToken: creds.refreshToken }),\n });\n if (!res.ok) {\n throw new Error('Session expired. Run: kb auth login --gateway-url <url> --client-id <id> --client-secret <secret>');\n }\n const refreshed = await res.json() as { accessToken: string; refreshToken: string; expiresIn: number };\n creds = {\n ...creds,\n accessToken: refreshed.accessToken,\n refreshToken: refreshed.refreshToken,\n expiresAt: Date.now() + refreshed.expiresIn * 1000,\n };\n await writeFile(CREDENTIALS_PATH, JSON.stringify(creds, null, 2), 'utf-8');\n await chmod(CREDENTIALS_PATH, 0o600);\n }\n\n if (!creds.handle) {\n throw new Error(\n 'Author handle not set in credentials. Re-run:\\n kb auth login --gateway-url <url> --client-id <id> --client-secret <secret>',\n );\n }\n\n // 3. credentials + KB_REGISTRY_URL override (execution gateway ≠ registry URL)\n // 4. credentials fully (gatewayUrl used to derive registry base URL)\n const baseUrl = envRegUrl\n ? envRegUrl.replace(/\\/$/, '')\n : `${creds.gatewayUrl.replace(/\\/$/, '')}${REGISTRY_GATEWAY_PREFIX}`;\n\n return { token: creds.accessToken, baseUrl, handle: creds.handle };\n}\n\n/**\n * Resolve the author handle from the credential provider chain.\n * Used when the handle is needed explicitly (e.g. for URL path construction).\n */\nexport async function resolveRegistryHandle(): Promise<string> {\n const auth = await resolveAuth();\n return auth.handle;\n}\n\nexport async function registryPost<T = unknown>(\n path: string,\n body: Record<string, unknown>,\n token?: string,\n): Promise<T> {\n const auth = token\n ? { token, baseUrl: resolveBaseUrlFromEnv() }\n : await resolveAuth();\n\n const url = `${auth.baseUrl}${path}`;\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);\n try {\n const res = await fetch(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${auth.token}` },\n body: JSON.stringify(body),\n signal: controller.signal,\n });\n if (!res.ok) {\n const text = await res.text();\n throw new Error(`Registry ${path} failed (${res.status}): ${text}`);\n }\n if (res.status === 204) { return undefined as T; }\n return await res.json() as T;\n } catch (err) {\n if ((err as Error).name === 'AbortError') {\n throw new Error('Registry request timed out. Is the gateway reachable?');\n }\n throw err;\n } finally {\n clearTimeout(timer);\n }\n}\n\nexport async function registryPostMultipart<T = unknown>(\n path: string,\n tarball: Buffer,\n fields: Record<string, string>,\n token?: string,\n authorHandle?: string,\n): Promise<T> {\n const auth = token\n ? {\n token,\n baseUrl: resolveBaseUrlFromEnv(),\n handle: authorHandle ?? useEnv('KB_REGISTRY_AUTHOR_HANDLE') ?? '',\n }\n : await resolveAuth();\n\n const url = `${auth.baseUrl}${path}`;\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);\n try {\n const form = new FormData();\n form.append('tarball', new Blob([tarball], { type: 'application/octet-stream' }), 'package.tgz');\n for (const [k, v] of Object.entries(fields)) { form.append(k, v); }\n\n const handleHeader: Record<string, string> = auth.handle ? { 'X-Author-Handle': auth.handle } : {};\n\n const res = await fetch(url, {\n method: 'POST',\n headers: { Authorization: `Bearer ${auth.token}`, ...handleHeader },\n body: form,\n signal: controller.signal,\n });\n if (!res.ok) {\n const text = await res.text();\n throw new Error(`Registry publish failed (${res.status}): ${text}`);\n }\n return await res.json() as T;\n } catch (err) {\n if ((err as Error).name === 'AbortError') {\n throw new Error('Registry publish timed out.');\n }\n throw err;\n } finally {\n clearTimeout(timer);\n }\n}\n\nexport async function registryPatch<T = unknown>(\n path: string,\n body: Record<string, unknown>,\n token?: string,\n): Promise<T> {\n const auth = token\n ? { token, baseUrl: resolveBaseUrlFromEnv() }\n : await resolveAuth();\n\n const url = `${auth.baseUrl}${path}`;\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);\n try {\n const res = await fetch(url, {\n method: 'PATCH',\n headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${auth.token}` },\n body: JSON.stringify(body),\n signal: controller.signal,\n });\n if (!res.ok) {\n const text = await res.text();\n throw new Error(`Registry ${path} failed (${res.status}): ${text}`);\n }\n if (res.status === 204) { return undefined as T; }\n return await res.json() as T;\n } catch (err) {\n if ((err as Error).name === 'AbortError') {\n throw new Error('Registry request timed out.');\n }\n throw err;\n } finally {\n clearTimeout(timer);\n }\n}\n","import { defineCommand, handleError, validationError, type CLIInput, type PluginContextV3 } from '@kb-labs/sdk';\nimport { registryPost } from '../registry-http.js';\n\ninterface ShareFlags {\n with?: string;\n link?: boolean;\n ttl?: string;\n json?: boolean;\n}\n\ninterface ShareTokenResult {\n token?: string;\n pkg?: string;\n expiresAt?: string;\n}\n\nexport default defineCommand<unknown, CLIInput<ShareFlags>, { exitCode: number }>({\n id: 'marketplace:share',\n description: 'Share a private plugin (--with or --link)',\n\n handler: {\n async execute(ctx: PluginContextV3, input: CLIInput<ShareFlags>): Promise<{ exitCode: number }> {\n const { flags = {}, argv = [] } = input;\n const pkg = argv[0];\n const t0 = Date.now();\n\n if (!pkg) {\n validationError(ctx, 'Package spec is required', 'Usage: kb marketplace share kb:handle/name [--with handle | --link]', flags.json);\n return { exitCode: 1 };\n }\n\n if (!flags.with && !flags.link) {\n validationError(ctx, 'Specify --with <handle> to grant access, or --link to generate a share token', undefined, flags.json);\n return { exitCode: 1 };\n }\n\n if (!pkg.startsWith('kb:')) {\n validationError(ctx, 'Package must be a kb: spec', 'Example: kb:kirill/my-plugin', flags.json);\n return { exitCode: 1 };\n }\n\n const sliced = pkg.slice(3);\n const slashIdx = sliced.indexOf('/');\n const handle = slashIdx > 0 ? sliced.slice(0, slashIdx) : '';\n const name = slashIdx > 0 ? sliced.slice(slashIdx + 1) : '';\n if (!handle || !name) {\n validationError(ctx, 'Invalid kb: spec — expected kb:handle/name', undefined, flags.json);\n return { exitCode: 1 };\n }\n\n try {\n if (flags.with) {\n await registryPost(`/packages/${handle}/${encodeURIComponent(name)}/share/allowlist`, { namespaceId: flags.with });\n\n if (flags.json) {\n ctx.ui?.json?.({ added: flags.with, pkg });\n return { exitCode: 0 };\n }\n\n ctx.ui?.success?.(`${flags.with} can now install ${pkg}`, {\n sections: [\n {\n header: 'Install command for them',\n items: [{ text: `kb marketplace install ${pkg}`, truncate: 500 }],\n },\n ],\n hint: 'For one-time access without an account, use --link instead',\n timing: Date.now() - t0,\n });\n return { exitCode: 0 };\n }\n\n const ttlDays = flags.ttl ? parseInt(flags.ttl, 10) : 7;\n const result = await registryPost<ShareTokenResult>(`/packages/${handle}/${encodeURIComponent(name)}/share/token`, { ttlDays });\n\n if (flags.json) {\n ctx.ui?.json?.(result);\n return { exitCode: 0 };\n }\n\n const expiry = result.expiresAt\n ? new Date(result.expiresAt).toLocaleDateString()\n : `${ttlDays} days`;\n\n ctx.ui?.success?.('Share link created', {\n summary: {\n 'Token': result.token ?? '–',\n 'Expires': expiry,\n 'Package': pkg,\n },\n sections: [{\n header: 'Send this command to share',\n items: [{ text: `kb marketplace install ${pkg} --token ${result.token}`, truncate: 500 }],\n }],\n timing: Date.now() - t0,\n });\n\n return { exitCode: 0 };\n } catch (err) {\n handleError(ctx, err, flags.json);\n return { exitCode: 1 };\n }\n },\n },\n});\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/registry-http.ts","../../src/commands/share.ts"],"names":[],"mappings":"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","file":"share.js","sourcesContent":["/**\n * HTTP client for KB Labs Registry service.\n *\n * Credential provider chain (in priority order):\n * 1. KB_REGISTRY_URL + KB_REGISTRY_TOKEN — explicit registry URL (CI/CD, closed-loop mirror)\n * 2. KB_GATEWAY_URL + KB_REGISTRY_TOKEN — legacy CI/CD (derives registry URL from gateway)\n * 3. ~/.kb/credentials.json + KB_REGISTRY_URL — credentials file with explicit registry URL override\n * 4. ~/.kb/credentials.json fully — credentials file, derives registry URL from gatewayUrl\n * 5. Error — \"Run: kb auth login\"\n *\n * KB_REGISTRY_URL decouples the data layer (where the registry lives) from the execution\n * layer (which gateway runs the CLI command). Useful when the registry is behind a different\n * URL than the execution gateway — e.g. closed-loop mirrors or local dev pointing to prod registry.\n *\n * Token auto-refresh: if accessToken is within 60s of expiry, exchanges refreshToken\n * via POST /auth/refresh and overwrites ~/.kb/credentials.json (chmod 600).\n */\n\nimport { readFile, writeFile, chmod } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { homedir } from 'node:os';\nimport { useEnv } from '@kb-labs/sdk';\n\nconst CREDENTIALS_PATH = join(homedir(), '.kb', 'credentials.json');\nconst REGISTRY_GATEWAY_PREFIX = '/api/v1/registry';\nconst FETCH_TIMEOUT_MS = 60_000;\nconst EXPIRY_BUFFER_MS = 60_000;\n\ninterface ResolvedAuth {\n token: string;\n baseUrl: string; // full registry base URL including /api/v1/registry prefix\n handle: string;\n}\n\ninterface StoredCredentials {\n gatewayUrl: string;\n accessToken: string;\n refreshToken: string;\n expiresAt: number;\n handle?: string;\n namespaceId?: string;\n}\n\n/**\n * Resolve registry base URL from env vars only (used when a token is passed explicitly).\n * Priority: KB_REGISTRY_URL → KB_GATEWAY_URL → localhost fallback.\n */\nfunction resolveBaseUrlFromEnv(): string {\n const regUrl = useEnv('KB_REGISTRY_URL');\n const gateway = useEnv('KB_GATEWAY_URL');\n if (regUrl) { return regUrl.replace(/\\/$/, ''); }\n if (gateway) { return `${gateway.replace(/\\/$/, '')}${REGISTRY_GATEWAY_PREFIX}`; }\n return `http://127.0.0.1:4000${REGISTRY_GATEWAY_PREFIX}`;\n}\n\nasync function resolveAuth(): Promise<ResolvedAuth> {\n const envToken = useEnv('KB_REGISTRY_TOKEN');\n const envRegUrl = useEnv('KB_REGISTRY_URL'); // explicit registry base URL (data layer)\n const envGateway = useEnv('KB_GATEWAY_URL'); // legacy: derive registry URL from gateway\n const envHandle = useEnv('KB_REGISTRY_AUTHOR_HANDLE');\n\n // 1. Explicit registry URL + token (CI/CD, closed-loop mirror)\n if (envToken && envRegUrl) {\n return { token: envToken, baseUrl: envRegUrl.replace(/\\/$/, ''), handle: envHandle ?? '' };\n }\n\n // 2. Legacy: token + gateway URL → derive registry base URL\n if (envToken && envGateway) {\n return {\n token: envToken,\n baseUrl: `${envGateway.replace(/\\/$/, '')}${REGISTRY_GATEWAY_PREFIX}`,\n handle: envHandle ?? '',\n };\n }\n\n // 3–4. ~/.kb/credentials.json\n let creds: StoredCredentials;\n try {\n creds = JSON.parse(await readFile(CREDENTIALS_PATH, 'utf-8')) as StoredCredentials;\n } catch {\n throw new Error(\n 'Not authenticated. Run:\\n kb auth login --gateway-url <url> --email <email> --password <password>\\n kb auth register --gateway-url <url> --name <name> --namespace-id <ns>\\n kb auth login --gateway-url <url> --client-id <id> --client-secret <secret>',\n );\n }\n\n // Auto-refresh if token is expired or close to expiry\n if (Date.now() >= creds.expiresAt - EXPIRY_BUFFER_MS) {\n const res = await fetch(`${creds.gatewayUrl}/auth/refresh`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ refreshToken: creds.refreshToken }),\n });\n if (!res.ok) {\n throw new Error('Session expired. Run: kb auth login --gateway-url <url> --client-id <id> --client-secret <secret>');\n }\n const refreshed = await res.json() as { accessToken: string; refreshToken: string; expiresIn: number };\n creds = {\n ...creds,\n accessToken: refreshed.accessToken,\n refreshToken: refreshed.refreshToken,\n expiresAt: Date.now() + refreshed.expiresIn * 1000,\n };\n await writeFile(CREDENTIALS_PATH, JSON.stringify(creds, null, 2), 'utf-8');\n await chmod(CREDENTIALS_PATH, 0o600);\n }\n\n if (!creds.handle) {\n throw new Error(\n 'Author handle not set in credentials. Re-run:\\n kb auth login --gateway-url <url> --client-id <id> --client-secret <secret>',\n );\n }\n\n // 3. credentials + KB_REGISTRY_URL override (execution gateway ≠ registry URL)\n // 4. credentials fully (gatewayUrl used to derive registry base URL)\n const baseUrl = envRegUrl\n ? envRegUrl.replace(/\\/$/, '')\n : `${creds.gatewayUrl.replace(/\\/$/, '')}${REGISTRY_GATEWAY_PREFIX}`;\n\n return { token: creds.accessToken, baseUrl, handle: creds.handle };\n}\n\n/**\n * Resolve the author handle from the credential provider chain.\n * Used when the handle is needed explicitly (e.g. for URL path construction).\n */\nexport async function resolveRegistryHandle(): Promise<string> {\n const auth = await resolveAuth();\n return auth.handle;\n}\n\nexport async function registryPost<T = unknown>(\n path: string,\n body: Record<string, unknown>,\n token?: string,\n): Promise<T> {\n const auth = token\n ? { token, baseUrl: resolveBaseUrlFromEnv() }\n : await resolveAuth();\n\n const url = `${auth.baseUrl}${path}`;\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);\n try {\n const res = await fetch(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${auth.token}` },\n body: JSON.stringify(body),\n signal: controller.signal,\n });\n if (!res.ok) {\n const text = await res.text();\n throw new Error(`Registry ${path} failed (${res.status}): ${text}`);\n }\n if (res.status === 204) { return undefined as T; }\n return await res.json() as T;\n } catch (err) {\n if ((err as Error).name === 'AbortError') {\n throw new Error('Registry request timed out. Is the gateway reachable?');\n }\n throw err;\n } finally {\n clearTimeout(timer);\n }\n}\n\nexport async function registryPostMultipart<T = unknown>(\n path: string,\n tarball: Buffer,\n fields: Record<string, string>,\n token?: string,\n authorHandle?: string,\n): Promise<T> {\n const auth = token\n ? {\n token,\n baseUrl: resolveBaseUrlFromEnv(),\n handle: authorHandle ?? useEnv('KB_REGISTRY_AUTHOR_HANDLE') ?? '',\n }\n : await resolveAuth();\n\n const url = `${auth.baseUrl}${path}`;\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);\n try {\n const form = new FormData();\n form.append('tarball', new Blob([tarball], { type: 'application/octet-stream' }), 'package.tgz');\n for (const [k, v] of Object.entries(fields)) { form.append(k, v); }\n\n const handleHeader: Record<string, string> = auth.handle ? { 'X-Author-Handle': auth.handle } : {};\n\n const res = await fetch(url, {\n method: 'POST',\n headers: { Authorization: `Bearer ${auth.token}`, ...handleHeader },\n body: form,\n signal: controller.signal,\n });\n if (!res.ok) {\n const text = await res.text();\n throw new Error(`Registry publish failed (${res.status}): ${text}`);\n }\n return await res.json() as T;\n } catch (err) {\n if ((err as Error).name === 'AbortError') {\n throw new Error('Registry publish timed out.');\n }\n throw err;\n } finally {\n clearTimeout(timer);\n }\n}\n\nexport async function registryPatch<T = unknown>(\n path: string,\n body: Record<string, unknown>,\n token?: string,\n): Promise<T> {\n const auth = token\n ? { token, baseUrl: resolveBaseUrlFromEnv() }\n : await resolveAuth();\n\n const url = `${auth.baseUrl}${path}`;\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);\n try {\n const res = await fetch(url, {\n method: 'PATCH',\n headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${auth.token}` },\n body: JSON.stringify(body),\n signal: controller.signal,\n });\n if (!res.ok) {\n const text = await res.text();\n throw new Error(`Registry ${path} failed (${res.status}): ${text}`);\n }\n if (res.status === 204) { return undefined as T; }\n return await res.json() as T;\n } catch (err) {\n if ((err as Error).name === 'AbortError') {\n throw new Error('Registry request timed out.');\n }\n throw err;\n } finally {\n clearTimeout(timer);\n }\n}\n","import { defineCommand, handleError, validationError, type CLIInput, type PluginContextV3, type CommandResult } from '@kb-labs/sdk';\nimport { registryPost } from '../registry-http.js';\n\ninterface ShareFlags {\n with?: string;\n link?: boolean;\n ttl?: string;\n json?: boolean;\n}\n\ninterface ShareTokenResult {\n token?: string;\n pkg?: string;\n expiresAt?: string;\n}\n\nexport default defineCommand<unknown, CLIInput<ShareFlags>, ShareTokenResult>({\n id: 'marketplace:share',\n description: 'Share a private plugin (--with or --link)',\n\n handler: {\n async execute(ctx: PluginContextV3, input: CLIInput<ShareFlags>): Promise<CommandResult<ShareTokenResult>> {\n const { flags = {}, argv = [] } = input;\n const pkg = argv[0];\n const t0 = Date.now();\n\n if (!pkg) {\n validationError(ctx, 'Package spec is required', 'Usage: kb marketplace share kb:handle/name [--with handle | --link]', flags.json);\n return { ok: false, error: 'Package spec is required' };\n }\n\n if (!flags.with && !flags.link) {\n validationError(ctx, 'Specify --with <handle> to grant access, or --link to generate a share token', undefined, flags.json);\n return { ok: false, error: 'Specify --with or --link' };\n }\n\n if (!pkg.startsWith('kb:')) {\n validationError(ctx, 'Package must be a kb: spec', 'Example: kb:kirill/my-plugin', flags.json);\n return { ok: false, error: 'Package must be a kb: spec' };\n }\n\n const sliced = pkg.slice(3);\n const slashIdx = sliced.indexOf('/');\n const handle = slashIdx > 0 ? sliced.slice(0, slashIdx) : '';\n const name = slashIdx > 0 ? sliced.slice(slashIdx + 1) : '';\n if (!handle || !name) {\n validationError(ctx, 'Invalid kb: spec — expected kb:handle/name', undefined, flags.json);\n return { ok: false, error: 'Invalid kb: spec' };\n }\n\n try {\n if (flags.with) {\n await registryPost(`/packages/${handle}/${encodeURIComponent(name)}/share/allowlist`, { namespaceId: flags.with });\n\n if (flags.json) {\n ctx.ui?.json?.({ added: flags.with, pkg });\n return { ok: true };\n }\n\n ctx.ui?.success?.(`${flags.with} can now install ${pkg}`, {\n sections: [\n {\n header: 'Install command for them',\n items: [{ text: `kb marketplace install ${pkg}`, truncate: 500 }],\n },\n ],\n hint: 'For one-time access without an account, use --link instead',\n timing: Date.now() - t0,\n });\n return { ok: true };\n }\n\n const ttlDays = flags.ttl ? parseInt(flags.ttl, 10) : 7;\n const result = await registryPost<ShareTokenResult>(`/packages/${handle}/${encodeURIComponent(name)}/share/token`, { ttlDays });\n\n if (flags.json) {\n ctx.ui?.json?.(result);\n return { ok: true, result };\n }\n\n const expiry = result.expiresAt\n ? new Date(result.expiresAt).toLocaleDateString()\n : `${ttlDays} days`;\n\n ctx.ui?.success?.('Share link created', {\n summary: {\n 'Token': result.token ?? '–',\n 'Expires': expiry,\n 'Package': pkg,\n },\n sections: [{\n header: 'Send this command to share',\n items: [{ text: `kb marketplace install ${pkg} --token ${result.token}`, truncate: 500 }],\n }],\n timing: Date.now() - t0,\n });\n\n return { ok: true, result };\n } catch (err) {\n handleError(ctx, err, flags.json);\n return { ok: false, error: err instanceof Error ? err.message : String(err) };\n }\n },\n },\n});\n"]}
|
package/dist/commands/yank.d.ts
CHANGED
|
@@ -5,8 +5,6 @@ interface YankFlags {
|
|
|
5
5
|
reason?: string;
|
|
6
6
|
json?: boolean;
|
|
7
7
|
}
|
|
8
|
-
declare const _default: _kb_labs_shared_command_kit.CommandHandlerV3<unknown, CLIInput<YankFlags>,
|
|
9
|
-
exitCode: number;
|
|
10
|
-
}>;
|
|
8
|
+
declare const _default: _kb_labs_shared_command_kit.CommandHandlerV3<unknown, CLIInput<YankFlags>, unknown>;
|
|
11
9
|
|
|
12
10
|
export { _default as default };
|
package/dist/commands/yank.js
CHANGED
|
@@ -99,11 +99,11 @@ var yank_default = defineCommand({
|
|
|
99
99
|
const t0 = Date.now();
|
|
100
100
|
if (!pkg || !version) {
|
|
101
101
|
validationError(ctx, "Package spec and version are required", "Usage: kb marketplace yank kb:handle/name <version>", flags.json);
|
|
102
|
-
return {
|
|
102
|
+
return { ok: false, error: "Package spec and version are required" };
|
|
103
103
|
}
|
|
104
104
|
if (!pkg.startsWith("kb:")) {
|
|
105
105
|
validationError(ctx, "Package must be a kb: spec", "Example: kb:kirill/my-plugin", flags.json);
|
|
106
|
-
return {
|
|
106
|
+
return { ok: false, error: "Package must be a kb: spec" };
|
|
107
107
|
}
|
|
108
108
|
const sliced = pkg.slice(3);
|
|
109
109
|
const slashIdx = sliced.indexOf("/");
|
|
@@ -111,13 +111,13 @@ var yank_default = defineCommand({
|
|
|
111
111
|
const name = slashIdx > 0 ? sliced.slice(slashIdx + 1) : "";
|
|
112
112
|
if (!handle || !name) {
|
|
113
113
|
validationError(ctx, "Invalid kb: spec \u2014 expected kb:handle/name", void 0, flags.json);
|
|
114
|
-
return {
|
|
114
|
+
return { ok: false, error: "Invalid kb: spec" };
|
|
115
115
|
}
|
|
116
116
|
try {
|
|
117
117
|
await registryPost(`/packages/${handle}/${encodeURIComponent(name)}/${version}/yank`, { reason: flags.reason });
|
|
118
118
|
if (flags.json) {
|
|
119
119
|
ctx.ui?.json?.({ yanked: true, pkg, version });
|
|
120
|
-
return {
|
|
120
|
+
return { ok: true };
|
|
121
121
|
}
|
|
122
122
|
const items = [
|
|
123
123
|
"Fresh installs of this version are blocked",
|
|
@@ -131,10 +131,10 @@ var yank_default = defineCommand({
|
|
|
131
131
|
hint: "To yank all versions, deprecate the package instead",
|
|
132
132
|
timing: Date.now() - t0
|
|
133
133
|
});
|
|
134
|
-
return {
|
|
134
|
+
return { ok: true };
|
|
135
135
|
} catch (err) {
|
|
136
136
|
handleError(ctx, err, flags.json);
|
|
137
|
-
return {
|
|
137
|
+
return { ok: false, error: err instanceof Error ? err.message : String(err) };
|
|
138
138
|
}
|
|
139
139
|
}
|
|
140
140
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/registry-http.ts","../../src/commands/yank.ts"],"names":[],"mappings":";;;;;;AAuBA,IAAM,gBAAA,GAAmB,IAAA,CAAK,OAAA,EAAQ,EAAG,OAAO,kBAAkB,CAAA;AAClE,IAAM,uBAAA,GAA0B,kBAAA;AAChC,IAAM,gBAAA,GAAmB,GAAA;AACzB,IAAM,gBAAA,GAAmB,GAAA;AA6BzB,eAAe,WAAA,GAAqC;AAClD,EAAA,MAAM,QAAA,GAAa,OAAO,mBAAmB,CAAA;AAC7C,EAAA,MAAM,SAAA,GAAa,OAAO,iBAAiB,CAAA;AAC3C,EAAA,MAAM,UAAA,GAAa,OAAO,gBAAgB,CAAA;AAC1C,EAAA,MAAM,SAAA,GAAa,OAAO,2BAA2B,CAAA;AAGrD,EAAA,IAAI,YAAY,SAAA,EAAW;AACzB,IAAA,OAAO,EAAE,KAAA,EAAO,QAAA,EAAU,OAAA,EAAS,SAAA,CAAU,OAAA,CAAQ,KAAA,EAAO,EAAE,CAAA,EAAG,MAAA,EAAQ,SAAA,IAAa,EAAA,EAAG;AAAA,EAC3F;AAGA,EAAA,IAAI,YAAY,UAAA,EAAY;AAC1B,IAAA,OAAO;AAAA,MACL,KAAA,EAAO,QAAA;AAAA,MACP,OAAA,EAAS,GAAG,UAAA,CAAW,OAAA,CAAQ,OAAO,EAAE,CAAC,GAAG,uBAAuB,CAAA,CAAA;AAAA,MACnE,QAAQ,SAAA,IAAa;AAAA,KACvB;AAAA,EACF;AAGA,EAAA,IAAI,KAAA;AACJ,EAAA,IAAI;AACF,IAAA,KAAA,GAAQ,KAAK,KAAA,CAAM,MAAM,QAAA,CAAS,gBAAA,EAAkB,OAAO,CAAC,CAAA;AAAA,EAC9D,CAAA,CAAA,MAAQ;AACN,IAAA,MAAM,IAAI,KAAA;AAAA,MACR;AAAA,KACF;AAAA,EACF;AAGA,EAAA,IAAI,IAAA,CAAK,GAAA,EAAI,IAAK,KAAA,CAAM,YAAY,gBAAA,EAAkB;AACpD,IAAA,MAAM,MAAM,MAAM,KAAA,CAAM,CAAA,EAAG,KAAA,CAAM,UAAU,CAAA,aAAA,CAAA,EAAiB;AAAA,MAC1D,MAAA,EAAQ,MAAA;AAAA,MACR,OAAA,EAAS,EAAE,cAAA,EAAgB,kBAAA,EAAmB;AAAA,MAC9C,MAAM,IAAA,CAAK,SAAA,CAAU,EAAE,YAAA,EAAc,KAAA,CAAM,cAAc;AAAA,KAC1D,CAAA;AACD,IAAA,IAAI,CAAC,IAAI,EAAA,EAAI;AACX,MAAA,MAAM,IAAI,MAAM,mGAAmG,CAAA;AAAA,IACrH;AACA,IAAA,MAAM,SAAA,GAAY,MAAM,GAAA,CAAI,IAAA,EAAK;AACjC,IAAA,KAAA,GAAQ;AAAA,MACN,GAAG,KAAA;AAAA,MACH,aAAa,SAAA,CAAU,WAAA;AAAA,MACvB,cAAc,SAAA,CAAU,YAAA;AAAA,MACxB,SAAA,EAAW,IAAA,CAAK,GAAA,EAAI,GAAI,UAAU,SAAA,GAAY;AAAA,KAChD;AACA,IAAA,MAAM,SAAA,CAAU,kBAAkB,IAAA,CAAK,SAAA,CAAU,OAAO,IAAA,EAAM,CAAC,GAAG,OAAO,CAAA;AACzE,IAAA,MAAM,KAAA,CAAM,kBAAkB,GAAK,CAAA;AAAA,EACrC;AAEA,EAAA,IAAI,CAAC,MAAM,MAAA,EAAQ;AACjB,IAAA,MAAM,IAAI,KAAA;AAAA,MACR;AAAA,KACF;AAAA,EACF;AAIA,EAAA,MAAM,OAAA,GAAU,SAAA,GACZ,SAAA,CAAU,OAAA,CAAQ,OAAO,EAAE,CAAA,GAC3B,CAAA,EAAG,KAAA,CAAM,WAAW,OAAA,CAAQ,KAAA,EAAO,EAAE,CAAC,GAAG,uBAAuB,CAAA,CAAA;AAEpE,EAAA,OAAO,EAAE,KAAA,EAAO,KAAA,CAAM,aAAa,OAAA,EAAS,MAAA,EAAQ,MAAM,MAAA,EAAO;AACnE;AAWA,eAAsB,YAAA,CACpB,IAAA,EACA,IAAA,EACA,KAAA,EACY;AACZ,EAAA,MAAM,IAAA,GAEF,MAAM,WAAA,EAAY;AAEtB,EAAA,MAAM,GAAA,GAAM,CAAA,EAAG,IAAA,CAAK,OAAO,GAAG,IAAI,CAAA,CAAA;AAClC,EAAA,MAAM,UAAA,GAAa,IAAI,eAAA,EAAgB;AACvC,EAAA,MAAM,QAAQ,UAAA,CAAW,MAAM,UAAA,CAAW,KAAA,IAAS,gBAAgB,CAAA;AACnE,EAAA,IAAI;AACF,IAAA,MAAM,GAAA,GAAM,MAAM,KAAA,CAAM,GAAA,EAAK;AAAA,MAC3B,MAAA,EAAQ,MAAA;AAAA,MACR,OAAA,EAAS,EAAE,cAAA,EAAgB,kBAAA,EAAoB,eAAe,CAAA,OAAA,EAAU,IAAA,CAAK,KAAK,CAAA,CAAA,EAAG;AAAA,MACrF,IAAA,EAAM,IAAA,CAAK,SAAA,CAAU,IAAI,CAAA;AAAA,MACzB,QAAQ,UAAA,CAAW;AAAA,KACpB,CAAA;AACD,IAAA,IAAI,CAAC,IAAI,EAAA,EAAI;AACX,MAAA,MAAM,IAAA,GAAO,MAAM,GAAA,CAAI,IAAA,EAAK;AAC5B,MAAA,MAAM,IAAI,MAAM,CAAA,SAAA,EAAY,IAAI,YAAY,GAAA,CAAI,MAAM,CAAA,GAAA,EAAM,IAAI,CAAA,CAAE,CAAA;AAAA,IACpE;AACA,IAAA,IAAI,GAAA,CAAI,WAAW,GAAA,EAAK;AAAE,MAAA,OAAO,KAAA,CAAA;AAAA,IAAgB;AACjD,IAAA,OAAO,MAAM,IAAI,IAAA,EAAK;AAAA,EACxB,SAAS,GAAA,EAAK;AACZ,IAAA,IAAK,GAAA,CAAc,SAAS,YAAA,EAAc;AACxC,MAAA,MAAM,IAAI,MAAM,uDAAuD,CAAA;AAAA,IACzE;AACA,IAAA,MAAM,GAAA;AAAA,EACR,CAAA,SAAE;AACA,IAAA,YAAA,CAAa,KAAK,CAAA;AAAA,EACpB;AACF;;;AC3JA,IAAO,eAAQ,aAAA,CAAkE;AAAA,EAC/E,EAAA,EAAI,kBAAA;AAAA,EACJ,WAAA,EAAa,oFAAA;AAAA,EAEb,OAAA,EAAS;AAAA,IACP,MAAM,OAAA,CAAQ,GAAA,EAAsB,KAAA,EAA2D;AAC7F,MAAA,MAAM,EAAE,KAAA,GAAQ,IAAI,IAAA,GAAO,IAAG,GAAI,KAAA;AAClC,MAAA,MAAM,CAAC,GAAA,EAAK,OAAO,CAAA,GAAI,IAAA;AACvB,MAAA,MAAM,EAAA,GAAK,KAAK,GAAA,EAAI;AAEpB,MAAA,IAAI,CAAC,GAAA,IAAO,CAAC,OAAA,EAAS;AACpB,QAAA,eAAA,CAAgB,GAAA,EAAK,uCAAA,EAAyC,qDAAA,EAAuD,KAAA,CAAM,IAAI,CAAA;AAC/H,QAAA,OAAO,EAAE,UAAU,CAAA,EAAE;AAAA,MACvB;AAEA,MAAA,IAAI,CAAC,GAAA,CAAI,UAAA,CAAW,KAAK,CAAA,EAAG;AAC1B,QAAA,eAAA,CAAgB,GAAA,EAAK,4BAAA,EAA8B,8BAAA,EAAgC,KAAA,CAAM,IAAI,CAAA;AAC7F,QAAA,OAAO,EAAE,UAAU,CAAA,EAAE;AAAA,MACvB;AAEA,MAAA,MAAM,MAAA,GAAS,GAAA,CAAI,KAAA,CAAM,CAAC,CAAA;AAC1B,MAAA,MAAM,QAAA,GAAW,MAAA,CAAO,OAAA,CAAQ,GAAG,CAAA;AACnC,MAAA,MAAM,SAAS,QAAA,GAAW,CAAA,GAAI,OAAO,KAAA,CAAM,CAAA,EAAG,QAAQ,CAAA,GAAI,EAAA;AAC1D,MAAA,MAAM,OAAO,QAAA,GAAW,CAAA,GAAI,OAAO,KAAA,CAAM,QAAA,GAAW,CAAC,CAAA,GAAI,EAAA;AACzD,MAAA,IAAI,CAAC,MAAA,IAAU,CAAC,IAAA,EAAM;AACpB,QAAA,eAAA,CAAgB,GAAA,EAAK,iDAAA,EAA8C,MAAA,EAAW,KAAA,CAAM,IAAI,CAAA;AACxF,QAAA,OAAO,EAAE,UAAU,CAAA,EAAE;AAAA,MACvB;AAEA,MAAA,IAAI;AACF,QAAA,MAAM,YAAA,CAAa,CAAA,UAAA,EAAa,MAAM,CAAA,CAAA,EAAI,mBAAmB,IAAI,CAAC,CAAA,CAAA,EAAI,OAAO,CAAA,KAAA,CAAA,EAAS,EAAE,MAAA,EAAQ,KAAA,CAAM,QAAQ,CAAA;AAE9G,QAAA,IAAI,MAAM,IAAA,EAAM;AACd,UAAA,GAAA,CAAI,IAAI,IAAA,GAAO,EAAE,QAAQ,IAAA,EAAM,GAAA,EAAK,SAAS,CAAA;AAC7C,UAAA,OAAO,EAAE,UAAU,CAAA,EAAE;AAAA,QACvB;AAEA,QAAA,MAAM,KAAA,GAAQ;AAAA,UACZ,4CAAA;AAAA,UACA;AAAA,SACF;AACA,QAAA,IAAI,MAAM,MAAA,EAAQ;AAChB,UAAA,KAAA,CAAM,IAAA,CAAK,CAAA,QAAA,EAAW,KAAA,CAAM,MAAM,CAAA,CAAE,CAAA;AAAA,QACtC;AAEA,QAAA,GAAA,CAAI,IAAI,OAAA,GAAU,CAAA,EAAG,GAAG,CAAA,CAAA,EAAI,OAAO,CAAA,OAAA,CAAA,EAAW;AAAA,UAC5C,UAAU,CAAC,EAAE,MAAA,EAAQ,iBAAA,EAAmB,OAAO,CAAA;AAAA,UAC/C,IAAA,EAAM,qDAAA;AAAA,UACN,MAAA,EAAQ,IAAA,CAAK,GAAA,EAAI,GAAI;AAAA,SACtB,CAAA;AAED,QAAA,OAAO,EAAE,UAAU,CAAA,EAAE;AAAA,MACvB,SAAS,GAAA,EAAK;AACZ,QAAA,WAAA,CAAY,GAAA,EAAK,GAAA,EAAK,KAAA,CAAM,IAAI,CAAA;AAChC,QAAA,OAAO,EAAE,UAAU,CAAA,EAAE;AAAA,MACvB;AAAA,IACF;AAAA;AAEJ,CAAC","file":"yank.js","sourcesContent":["/**\n * HTTP client for KB Labs Registry service.\n *\n * Credential provider chain (in priority order):\n * 1. KB_REGISTRY_URL + KB_REGISTRY_TOKEN — explicit registry URL (CI/CD, closed-loop mirror)\n * 2. KB_GATEWAY_URL + KB_REGISTRY_TOKEN — legacy CI/CD (derives registry URL from gateway)\n * 3. ~/.kb/credentials.json + KB_REGISTRY_URL — credentials file with explicit registry URL override\n * 4. ~/.kb/credentials.json fully — credentials file, derives registry URL from gatewayUrl\n * 5. Error — \"Run: kb auth login\"\n *\n * KB_REGISTRY_URL decouples the data layer (where the registry lives) from the execution\n * layer (which gateway runs the CLI command). Useful when the registry is behind a different\n * URL than the execution gateway — e.g. closed-loop mirrors or local dev pointing to prod registry.\n *\n * Token auto-refresh: if accessToken is within 60s of expiry, exchanges refreshToken\n * via POST /auth/refresh and overwrites ~/.kb/credentials.json (chmod 600).\n */\n\nimport { readFile, writeFile, chmod } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { homedir } from 'node:os';\nimport { useEnv } from '@kb-labs/sdk';\n\nconst CREDENTIALS_PATH = join(homedir(), '.kb', 'credentials.json');\nconst REGISTRY_GATEWAY_PREFIX = '/api/v1/registry';\nconst FETCH_TIMEOUT_MS = 60_000;\nconst EXPIRY_BUFFER_MS = 60_000;\n\ninterface ResolvedAuth {\n token: string;\n baseUrl: string; // full registry base URL including /api/v1/registry prefix\n handle: string;\n}\n\ninterface StoredCredentials {\n gatewayUrl: string;\n accessToken: string;\n refreshToken: string;\n expiresAt: number;\n handle?: string;\n namespaceId?: string;\n}\n\n/**\n * Resolve registry base URL from env vars only (used when a token is passed explicitly).\n * Priority: KB_REGISTRY_URL → KB_GATEWAY_URL → localhost fallback.\n */\nfunction resolveBaseUrlFromEnv(): string {\n const regUrl = useEnv('KB_REGISTRY_URL');\n const gateway = useEnv('KB_GATEWAY_URL');\n if (regUrl) { return regUrl.replace(/\\/$/, ''); }\n if (gateway) { return `${gateway.replace(/\\/$/, '')}${REGISTRY_GATEWAY_PREFIX}`; }\n return `http://127.0.0.1:4000${REGISTRY_GATEWAY_PREFIX}`;\n}\n\nasync function resolveAuth(): Promise<ResolvedAuth> {\n const envToken = useEnv('KB_REGISTRY_TOKEN');\n const envRegUrl = useEnv('KB_REGISTRY_URL'); // explicit registry base URL (data layer)\n const envGateway = useEnv('KB_GATEWAY_URL'); // legacy: derive registry URL from gateway\n const envHandle = useEnv('KB_REGISTRY_AUTHOR_HANDLE');\n\n // 1. Explicit registry URL + token (CI/CD, closed-loop mirror)\n if (envToken && envRegUrl) {\n return { token: envToken, baseUrl: envRegUrl.replace(/\\/$/, ''), handle: envHandle ?? '' };\n }\n\n // 2. Legacy: token + gateway URL → derive registry base URL\n if (envToken && envGateway) {\n return {\n token: envToken,\n baseUrl: `${envGateway.replace(/\\/$/, '')}${REGISTRY_GATEWAY_PREFIX}`,\n handle: envHandle ?? '',\n };\n }\n\n // 3–4. ~/.kb/credentials.json\n let creds: StoredCredentials;\n try {\n creds = JSON.parse(await readFile(CREDENTIALS_PATH, 'utf-8')) as StoredCredentials;\n } catch {\n throw new Error(\n 'Not authenticated. Run:\\n kb auth login --gateway-url <url> --email <email> --password <password>\\n kb auth register --gateway-url <url> --name <name> --namespace-id <ns>\\n kb auth login --gateway-url <url> --client-id <id> --client-secret <secret>',\n );\n }\n\n // Auto-refresh if token is expired or close to expiry\n if (Date.now() >= creds.expiresAt - EXPIRY_BUFFER_MS) {\n const res = await fetch(`${creds.gatewayUrl}/auth/refresh`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ refreshToken: creds.refreshToken }),\n });\n if (!res.ok) {\n throw new Error('Session expired. Run: kb auth login --gateway-url <url> --client-id <id> --client-secret <secret>');\n }\n const refreshed = await res.json() as { accessToken: string; refreshToken: string; expiresIn: number };\n creds = {\n ...creds,\n accessToken: refreshed.accessToken,\n refreshToken: refreshed.refreshToken,\n expiresAt: Date.now() + refreshed.expiresIn * 1000,\n };\n await writeFile(CREDENTIALS_PATH, JSON.stringify(creds, null, 2), 'utf-8');\n await chmod(CREDENTIALS_PATH, 0o600);\n }\n\n if (!creds.handle) {\n throw new Error(\n 'Author handle not set in credentials. Re-run:\\n kb auth login --gateway-url <url> --client-id <id> --client-secret <secret>',\n );\n }\n\n // 3. credentials + KB_REGISTRY_URL override (execution gateway ≠ registry URL)\n // 4. credentials fully (gatewayUrl used to derive registry base URL)\n const baseUrl = envRegUrl\n ? envRegUrl.replace(/\\/$/, '')\n : `${creds.gatewayUrl.replace(/\\/$/, '')}${REGISTRY_GATEWAY_PREFIX}`;\n\n return { token: creds.accessToken, baseUrl, handle: creds.handle };\n}\n\n/**\n * Resolve the author handle from the credential provider chain.\n * Used when the handle is needed explicitly (e.g. for URL path construction).\n */\nexport async function resolveRegistryHandle(): Promise<string> {\n const auth = await resolveAuth();\n return auth.handle;\n}\n\nexport async function registryPost<T = unknown>(\n path: string,\n body: Record<string, unknown>,\n token?: string,\n): Promise<T> {\n const auth = token\n ? { token, baseUrl: resolveBaseUrlFromEnv() }\n : await resolveAuth();\n\n const url = `${auth.baseUrl}${path}`;\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);\n try {\n const res = await fetch(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${auth.token}` },\n body: JSON.stringify(body),\n signal: controller.signal,\n });\n if (!res.ok) {\n const text = await res.text();\n throw new Error(`Registry ${path} failed (${res.status}): ${text}`);\n }\n if (res.status === 204) { return undefined as T; }\n return await res.json() as T;\n } catch (err) {\n if ((err as Error).name === 'AbortError') {\n throw new Error('Registry request timed out. Is the gateway reachable?');\n }\n throw err;\n } finally {\n clearTimeout(timer);\n }\n}\n\nexport async function registryPostMultipart<T = unknown>(\n path: string,\n tarball: Buffer,\n fields: Record<string, string>,\n token?: string,\n authorHandle?: string,\n): Promise<T> {\n const auth = token\n ? {\n token,\n baseUrl: resolveBaseUrlFromEnv(),\n handle: authorHandle ?? useEnv('KB_REGISTRY_AUTHOR_HANDLE') ?? '',\n }\n : await resolveAuth();\n\n const url = `${auth.baseUrl}${path}`;\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);\n try {\n const form = new FormData();\n form.append('tarball', new Blob([tarball], { type: 'application/octet-stream' }), 'package.tgz');\n for (const [k, v] of Object.entries(fields)) { form.append(k, v); }\n\n const handleHeader: Record<string, string> = auth.handle ? { 'X-Author-Handle': auth.handle } : {};\n\n const res = await fetch(url, {\n method: 'POST',\n headers: { Authorization: `Bearer ${auth.token}`, ...handleHeader },\n body: form,\n signal: controller.signal,\n });\n if (!res.ok) {\n const text = await res.text();\n throw new Error(`Registry publish failed (${res.status}): ${text}`);\n }\n return await res.json() as T;\n } catch (err) {\n if ((err as Error).name === 'AbortError') {\n throw new Error('Registry publish timed out.');\n }\n throw err;\n } finally {\n clearTimeout(timer);\n }\n}\n\nexport async function registryPatch<T = unknown>(\n path: string,\n body: Record<string, unknown>,\n token?: string,\n): Promise<T> {\n const auth = token\n ? { token, baseUrl: resolveBaseUrlFromEnv() }\n : await resolveAuth();\n\n const url = `${auth.baseUrl}${path}`;\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);\n try {\n const res = await fetch(url, {\n method: 'PATCH',\n headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${auth.token}` },\n body: JSON.stringify(body),\n signal: controller.signal,\n });\n if (!res.ok) {\n const text = await res.text();\n throw new Error(`Registry ${path} failed (${res.status}): ${text}`);\n }\n if (res.status === 204) { return undefined as T; }\n return await res.json() as T;\n } catch (err) {\n if ((err as Error).name === 'AbortError') {\n throw new Error('Registry request timed out.');\n }\n throw err;\n } finally {\n clearTimeout(timer);\n }\n}\n","import { defineCommand, handleError, validationError, type CLIInput, type PluginContextV3 } from '@kb-labs/sdk';\nimport { registryPost } from '../registry-http.js';\n\ninterface YankFlags {\n reason?: string;\n json?: boolean;\n}\n\nexport default defineCommand<unknown, CLIInput<YankFlags>, { exitCode: number }>({\n id: 'marketplace:yank',\n description: 'Yank a specific version (soft-remove — tarball stays, fresh installs blocked)',\n\n handler: {\n async execute(ctx: PluginContextV3, input: CLIInput<YankFlags>): Promise<{ exitCode: number }> {\n const { flags = {}, argv = [] } = input;\n const [pkg, version] = argv;\n const t0 = Date.now();\n\n if (!pkg || !version) {\n validationError(ctx, 'Package spec and version are required', 'Usage: kb marketplace yank kb:handle/name <version>', flags.json);\n return { exitCode: 1 };\n }\n\n if (!pkg.startsWith('kb:')) {\n validationError(ctx, 'Package must be a kb: spec', 'Example: kb:kirill/my-plugin', flags.json);\n return { exitCode: 1 };\n }\n\n const sliced = pkg.slice(3);\n const slashIdx = sliced.indexOf('/');\n const handle = slashIdx > 0 ? sliced.slice(0, slashIdx) : '';\n const name = slashIdx > 0 ? sliced.slice(slashIdx + 1) : '';\n if (!handle || !name) {\n validationError(ctx, 'Invalid kb: spec — expected kb:handle/name', undefined, flags.json);\n return { exitCode: 1 };\n }\n\n try {\n await registryPost(`/packages/${handle}/${encodeURIComponent(name)}/${version}/yank`, { reason: flags.reason });\n\n if (flags.json) {\n ctx.ui?.json?.({ yanked: true, pkg, version });\n return { exitCode: 0 };\n }\n\n const items = [\n 'Fresh installs of this version are blocked',\n 'Existing installations continue to work',\n ];\n if (flags.reason) {\n items.push(`Reason: ${flags.reason}`);\n }\n\n ctx.ui?.success?.(`${pkg}@${version} yanked`, {\n sections: [{ header: 'What this means', items }],\n hint: 'To yank all versions, deprecate the package instead',\n timing: Date.now() - t0,\n });\n\n return { exitCode: 0 };\n } catch (err) {\n handleError(ctx, err, flags.json);\n return { exitCode: 1 };\n }\n },\n },\n});\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/registry-http.ts","../../src/commands/yank.ts"],"names":[],"mappings":"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","file":"yank.js","sourcesContent":["/**\n * HTTP client for KB Labs Registry service.\n *\n * Credential provider chain (in priority order):\n * 1. KB_REGISTRY_URL + KB_REGISTRY_TOKEN — explicit registry URL (CI/CD, closed-loop mirror)\n * 2. KB_GATEWAY_URL + KB_REGISTRY_TOKEN — legacy CI/CD (derives registry URL from gateway)\n * 3. ~/.kb/credentials.json + KB_REGISTRY_URL — credentials file with explicit registry URL override\n * 4. ~/.kb/credentials.json fully — credentials file, derives registry URL from gatewayUrl\n * 5. Error — \"Run: kb auth login\"\n *\n * KB_REGISTRY_URL decouples the data layer (where the registry lives) from the execution\n * layer (which gateway runs the CLI command). Useful when the registry is behind a different\n * URL than the execution gateway — e.g. closed-loop mirrors or local dev pointing to prod registry.\n *\n * Token auto-refresh: if accessToken is within 60s of expiry, exchanges refreshToken\n * via POST /auth/refresh and overwrites ~/.kb/credentials.json (chmod 600).\n */\n\nimport { readFile, writeFile, chmod } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { homedir } from 'node:os';\nimport { useEnv } from '@kb-labs/sdk';\n\nconst CREDENTIALS_PATH = join(homedir(), '.kb', 'credentials.json');\nconst REGISTRY_GATEWAY_PREFIX = '/api/v1/registry';\nconst FETCH_TIMEOUT_MS = 60_000;\nconst EXPIRY_BUFFER_MS = 60_000;\n\ninterface ResolvedAuth {\n token: string;\n baseUrl: string; // full registry base URL including /api/v1/registry prefix\n handle: string;\n}\n\ninterface StoredCredentials {\n gatewayUrl: string;\n accessToken: string;\n refreshToken: string;\n expiresAt: number;\n handle?: string;\n namespaceId?: string;\n}\n\n/**\n * Resolve registry base URL from env vars only (used when a token is passed explicitly).\n * Priority: KB_REGISTRY_URL → KB_GATEWAY_URL → localhost fallback.\n */\nfunction resolveBaseUrlFromEnv(): string {\n const regUrl = useEnv('KB_REGISTRY_URL');\n const gateway = useEnv('KB_GATEWAY_URL');\n if (regUrl) { return regUrl.replace(/\\/$/, ''); }\n if (gateway) { return `${gateway.replace(/\\/$/, '')}${REGISTRY_GATEWAY_PREFIX}`; }\n return `http://127.0.0.1:4000${REGISTRY_GATEWAY_PREFIX}`;\n}\n\nasync function resolveAuth(): Promise<ResolvedAuth> {\n const envToken = useEnv('KB_REGISTRY_TOKEN');\n const envRegUrl = useEnv('KB_REGISTRY_URL'); // explicit registry base URL (data layer)\n const envGateway = useEnv('KB_GATEWAY_URL'); // legacy: derive registry URL from gateway\n const envHandle = useEnv('KB_REGISTRY_AUTHOR_HANDLE');\n\n // 1. Explicit registry URL + token (CI/CD, closed-loop mirror)\n if (envToken && envRegUrl) {\n return { token: envToken, baseUrl: envRegUrl.replace(/\\/$/, ''), handle: envHandle ?? '' };\n }\n\n // 2. Legacy: token + gateway URL → derive registry base URL\n if (envToken && envGateway) {\n return {\n token: envToken,\n baseUrl: `${envGateway.replace(/\\/$/, '')}${REGISTRY_GATEWAY_PREFIX}`,\n handle: envHandle ?? '',\n };\n }\n\n // 3–4. ~/.kb/credentials.json\n let creds: StoredCredentials;\n try {\n creds = JSON.parse(await readFile(CREDENTIALS_PATH, 'utf-8')) as StoredCredentials;\n } catch {\n throw new Error(\n 'Not authenticated. Run:\\n kb auth login --gateway-url <url> --email <email> --password <password>\\n kb auth register --gateway-url <url> --name <name> --namespace-id <ns>\\n kb auth login --gateway-url <url> --client-id <id> --client-secret <secret>',\n );\n }\n\n // Auto-refresh if token is expired or close to expiry\n if (Date.now() >= creds.expiresAt - EXPIRY_BUFFER_MS) {\n const res = await fetch(`${creds.gatewayUrl}/auth/refresh`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ refreshToken: creds.refreshToken }),\n });\n if (!res.ok) {\n throw new Error('Session expired. Run: kb auth login --gateway-url <url> --client-id <id> --client-secret <secret>');\n }\n const refreshed = await res.json() as { accessToken: string; refreshToken: string; expiresIn: number };\n creds = {\n ...creds,\n accessToken: refreshed.accessToken,\n refreshToken: refreshed.refreshToken,\n expiresAt: Date.now() + refreshed.expiresIn * 1000,\n };\n await writeFile(CREDENTIALS_PATH, JSON.stringify(creds, null, 2), 'utf-8');\n await chmod(CREDENTIALS_PATH, 0o600);\n }\n\n if (!creds.handle) {\n throw new Error(\n 'Author handle not set in credentials. Re-run:\\n kb auth login --gateway-url <url> --client-id <id> --client-secret <secret>',\n );\n }\n\n // 3. credentials + KB_REGISTRY_URL override (execution gateway ≠ registry URL)\n // 4. credentials fully (gatewayUrl used to derive registry base URL)\n const baseUrl = envRegUrl\n ? envRegUrl.replace(/\\/$/, '')\n : `${creds.gatewayUrl.replace(/\\/$/, '')}${REGISTRY_GATEWAY_PREFIX}`;\n\n return { token: creds.accessToken, baseUrl, handle: creds.handle };\n}\n\n/**\n * Resolve the author handle from the credential provider chain.\n * Used when the handle is needed explicitly (e.g. for URL path construction).\n */\nexport async function resolveRegistryHandle(): Promise<string> {\n const auth = await resolveAuth();\n return auth.handle;\n}\n\nexport async function registryPost<T = unknown>(\n path: string,\n body: Record<string, unknown>,\n token?: string,\n): Promise<T> {\n const auth = token\n ? { token, baseUrl: resolveBaseUrlFromEnv() }\n : await resolveAuth();\n\n const url = `${auth.baseUrl}${path}`;\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);\n try {\n const res = await fetch(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${auth.token}` },\n body: JSON.stringify(body),\n signal: controller.signal,\n });\n if (!res.ok) {\n const text = await res.text();\n throw new Error(`Registry ${path} failed (${res.status}): ${text}`);\n }\n if (res.status === 204) { return undefined as T; }\n return await res.json() as T;\n } catch (err) {\n if ((err as Error).name === 'AbortError') {\n throw new Error('Registry request timed out. Is the gateway reachable?');\n }\n throw err;\n } finally {\n clearTimeout(timer);\n }\n}\n\nexport async function registryPostMultipart<T = unknown>(\n path: string,\n tarball: Buffer,\n fields: Record<string, string>,\n token?: string,\n authorHandle?: string,\n): Promise<T> {\n const auth = token\n ? {\n token,\n baseUrl: resolveBaseUrlFromEnv(),\n handle: authorHandle ?? useEnv('KB_REGISTRY_AUTHOR_HANDLE') ?? '',\n }\n : await resolveAuth();\n\n const url = `${auth.baseUrl}${path}`;\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);\n try {\n const form = new FormData();\n form.append('tarball', new Blob([tarball], { type: 'application/octet-stream' }), 'package.tgz');\n for (const [k, v] of Object.entries(fields)) { form.append(k, v); }\n\n const handleHeader: Record<string, string> = auth.handle ? { 'X-Author-Handle': auth.handle } : {};\n\n const res = await fetch(url, {\n method: 'POST',\n headers: { Authorization: `Bearer ${auth.token}`, ...handleHeader },\n body: form,\n signal: controller.signal,\n });\n if (!res.ok) {\n const text = await res.text();\n throw new Error(`Registry publish failed (${res.status}): ${text}`);\n }\n return await res.json() as T;\n } catch (err) {\n if ((err as Error).name === 'AbortError') {\n throw new Error('Registry publish timed out.');\n }\n throw err;\n } finally {\n clearTimeout(timer);\n }\n}\n\nexport async function registryPatch<T = unknown>(\n path: string,\n body: Record<string, unknown>,\n token?: string,\n): Promise<T> {\n const auth = token\n ? { token, baseUrl: resolveBaseUrlFromEnv() }\n : await resolveAuth();\n\n const url = `${auth.baseUrl}${path}`;\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);\n try {\n const res = await fetch(url, {\n method: 'PATCH',\n headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${auth.token}` },\n body: JSON.stringify(body),\n signal: controller.signal,\n });\n if (!res.ok) {\n const text = await res.text();\n throw new Error(`Registry ${path} failed (${res.status}): ${text}`);\n }\n if (res.status === 204) { return undefined as T; }\n return await res.json() as T;\n } catch (err) {\n if ((err as Error).name === 'AbortError') {\n throw new Error('Registry request timed out.');\n }\n throw err;\n } finally {\n clearTimeout(timer);\n }\n}\n","import { defineCommand, handleError, validationError, type CLIInput, type PluginContextV3, type CommandResult } from '@kb-labs/sdk';\nimport { registryPost } from '../registry-http.js';\n\ninterface YankFlags {\n reason?: string;\n json?: boolean;\n}\n\nexport default defineCommand<unknown, CLIInput<YankFlags>, unknown>({\n id: 'marketplace:yank',\n description: 'Yank a specific version (soft-remove — tarball stays, fresh installs blocked)',\n\n handler: {\n async execute(ctx: PluginContextV3, input: CLIInput<YankFlags>): Promise<CommandResult> {\n const { flags = {}, argv = [] } = input;\n const [pkg, version] = argv;\n const t0 = Date.now();\n\n if (!pkg || !version) {\n validationError(ctx, 'Package spec and version are required', 'Usage: kb marketplace yank kb:handle/name <version>', flags.json);\n return { ok: false, error: 'Package spec and version are required' };\n }\n\n if (!pkg.startsWith('kb:')) {\n validationError(ctx, 'Package must be a kb: spec', 'Example: kb:kirill/my-plugin', flags.json);\n return { ok: false, error: 'Package must be a kb: spec' };\n }\n\n const sliced = pkg.slice(3);\n const slashIdx = sliced.indexOf('/');\n const handle = slashIdx > 0 ? sliced.slice(0, slashIdx) : '';\n const name = slashIdx > 0 ? sliced.slice(slashIdx + 1) : '';\n if (!handle || !name) {\n validationError(ctx, 'Invalid kb: spec — expected kb:handle/name', undefined, flags.json);\n return { ok: false, error: 'Invalid kb: spec' };\n }\n\n try {\n await registryPost(`/packages/${handle}/${encodeURIComponent(name)}/${version}/yank`, { reason: flags.reason });\n\n if (flags.json) {\n ctx.ui?.json?.({ yanked: true, pkg, version });\n return { ok: true };\n }\n\n const items = [\n 'Fresh installs of this version are blocked',\n 'Existing installations continue to work',\n ];\n if (flags.reason) {\n items.push(`Reason: ${flags.reason}`);\n }\n\n ctx.ui?.success?.(`${pkg}@${version} yanked`, {\n sections: [{ header: 'What this means', items }],\n hint: 'To yank all versions, deprecate the package instead',\n timing: Date.now() - t0,\n });\n\n return { ok: true };\n } catch (err) {\n handleError(ctx, err, flags.json);\n return { ok: false, error: err instanceof Error ? err.message : String(err) };\n }\n },\n },\n});\n"]}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kb-labs/marketplace-registry-entry",
|
|
3
3
|
"description": "CLI commands for publishing and managing plugins in KB Labs Registry",
|
|
4
|
-
"version": "2.
|
|
4
|
+
"version": "2.111.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
7
7
|
"types": "./dist/index.d.ts",
|