veryfront 0.1.130 → 0.1.131

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.
Files changed (78) hide show
  1. package/esm/cli/auth/login.d.ts.map +1 -1
  2. package/esm/cli/auth/login.js +11 -0
  3. package/esm/cli/auth/provider-store.d.ts +20 -0
  4. package/esm/cli/auth/provider-store.d.ts.map +1 -0
  5. package/esm/cli/auth/provider-store.js +62 -0
  6. package/esm/cli/auth/providers/anthropic.d.ts +2 -0
  7. package/esm/cli/auth/providers/anthropic.d.ts.map +1 -0
  8. package/esm/cli/auth/providers/anthropic.js +37 -0
  9. package/esm/cli/auth/providers/openai.d.ts +2 -0
  10. package/esm/cli/auth/providers/openai.d.ts.map +1 -0
  11. package/esm/cli/auth/providers/openai.js +35 -0
  12. package/esm/cli/auth/utils.d.ts +5 -0
  13. package/esm/cli/auth/utils.d.ts.map +1 -1
  14. package/esm/cli/auth/utils.js +9 -0
  15. package/esm/cli/router.d.ts.map +1 -1
  16. package/esm/cli/router.js +22 -1
  17. package/esm/deno.js +1 -1
  18. package/esm/src/channels/control-plane.js +6 -6
  19. package/esm/src/discovery/handlers/agent-handler.d.ts.map +1 -1
  20. package/esm/src/discovery/handlers/agent-handler.js +10 -1
  21. package/esm/src/rendering/rsc/client-boot.ts +18 -1
  22. package/esm/src/server/handlers/preview/markdown-html-generator.d.ts +2 -0
  23. package/esm/src/server/handlers/preview/markdown-html-generator.d.ts.map +1 -1
  24. package/esm/src/server/handlers/preview/markdown-html-generator.js +10 -7
  25. package/esm/src/server/handlers/preview/markdown-preview.handler.d.ts.map +1 -1
  26. package/esm/src/server/handlers/preview/markdown-preview.handler.js +6 -3
  27. package/esm/src/server/handlers/request/api/project-discovery.d.ts.map +1 -1
  28. package/esm/src/server/handlers/request/api/project-discovery.js +16 -5
  29. package/esm/src/server/handlers/request/api/security-headers.d.ts +1 -0
  30. package/esm/src/server/handlers/request/api/security-headers.d.ts.map +1 -1
  31. package/esm/src/server/handlers/request/api/security-headers.js +4 -1
  32. package/esm/src/server/handlers/request/openapi-docs.handler.d.ts.map +1 -1
  33. package/esm/src/server/handlers/request/openapi-docs.handler.js +10 -6
  34. package/esm/src/server/handlers/request/rsc/index.d.ts.map +1 -1
  35. package/esm/src/server/handlers/request/rsc/index.js +5 -2
  36. package/esm/src/server/handlers/request/ssr/ssr-response-builder.d.ts.map +1 -1
  37. package/esm/src/server/handlers/request/ssr/ssr-response-builder.js +12 -2
  38. package/esm/src/server/handlers/response/not-found.d.ts.map +1 -1
  39. package/esm/src/server/handlers/response/not-found.js +14 -15
  40. package/esm/src/server/services/rsc/endpoints/endpoint-router.d.ts +1 -1
  41. package/esm/src/server/services/rsc/endpoints/endpoint-router.d.ts.map +1 -1
  42. package/esm/src/server/services/rsc/endpoints/endpoint-router.js +3 -3
  43. package/esm/src/server/services/rsc/endpoints/rsc-bundles.generated.d.ts.map +1 -1
  44. package/esm/src/server/services/rsc/endpoints/rsc-bundles.generated.js +1 -1
  45. package/esm/src/server/services/rsc/endpoints/types.d.ts +1 -0
  46. package/esm/src/server/services/rsc/endpoints/types.d.ts.map +1 -1
  47. package/esm/src/server/services/rsc/orchestrators/handler.d.ts +1 -1
  48. package/esm/src/server/services/rsc/orchestrators/handler.d.ts.map +1 -1
  49. package/esm/src/server/services/rsc/orchestrators/handler.js +2 -2
  50. package/esm/src/server/services/rsc/orchestrators/page-handler.d.ts +1 -1
  51. package/esm/src/server/services/rsc/orchestrators/page-handler.d.ts.map +1 -1
  52. package/esm/src/server/services/rsc/orchestrators/page-handler.js +7 -5
  53. package/esm/src/utils/version-constant.d.ts +1 -1
  54. package/esm/src/utils/version-constant.js +1 -1
  55. package/package.json +1 -1
  56. package/src/cli/auth/login.ts +12 -0
  57. package/src/cli/auth/provider-store.ts +82 -0
  58. package/src/cli/auth/providers/anthropic.ts +46 -0
  59. package/src/cli/auth/providers/openai.ts +45 -0
  60. package/src/cli/auth/utils.ts +10 -0
  61. package/src/cli/router.ts +24 -1
  62. package/src/deno.js +1 -1
  63. package/src/src/channels/control-plane.ts +6 -6
  64. package/src/src/discovery/handlers/agent-handler.ts +10 -1
  65. package/src/src/server/handlers/preview/markdown-html-generator.ts +12 -6
  66. package/src/src/server/handlers/preview/markdown-preview.handler.ts +6 -3
  67. package/src/src/server/handlers/request/api/project-discovery.ts +18 -5
  68. package/src/src/server/handlers/request/api/security-headers.ts +10 -1
  69. package/src/src/server/handlers/request/openapi-docs.handler.ts +10 -6
  70. package/src/src/server/handlers/request/rsc/index.ts +5 -2
  71. package/src/src/server/handlers/request/ssr/ssr-response-builder.ts +16 -2
  72. package/src/src/server/handlers/response/not-found.ts +14 -15
  73. package/src/src/server/services/rsc/endpoints/endpoint-router.ts +3 -3
  74. package/src/src/server/services/rsc/endpoints/rsc-bundles.generated.ts +1 -1
  75. package/src/src/server/services/rsc/endpoints/types.ts +1 -0
  76. package/src/src/server/services/rsc/orchestrators/handler.ts +2 -2
  77. package/src/src/server/services/rsc/orchestrators/page-handler.ts +8 -5
  78. package/src/src/utils/version-constant.ts +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"login.d.ts","sourceRoot":"","sources":["../../../src/cli/auth/login.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,iBAAiB,EAAwB,MAAM,2BAA2B,CAAC;AACzF,OAAO,EAAE,WAAW,EAAoB,QAAQ,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAQjG,MAAM,MAAM,UAAU,GAAG,QAAQ,GAAG,QAAQ,GAAG,WAAW,GAAG,OAAO,CAAC;AAErE,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AASD,wBAAsB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAgB3E;AA8ID,wBAAsB,KAAK,CAAC,MAAM,CAAC,EAAE,UAAU,GAAG,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CA8BzE;AAED,wBAAsB,mBAAmB,CACvC,GAAG,GAAE,iBAA0C,GAC9C,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAqB1B;AAED,wBAAsB,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC,CAI5C;AAED,wBAAsB,MAAM,CAC1B,GAAG,GAAE,iBAA0C,GAC9C,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAuC1B;AAED,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS,EAAE,CAAC"}
1
+ {"version":3,"file":"login.d.ts","sourceRoot":"","sources":["../../../src/cli/auth/login.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,iBAAiB,EAAwB,MAAM,2BAA2B,CAAC;AACzF,OAAO,EAAE,WAAW,EAAoB,QAAQ,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAQjG,MAAM,MAAM,UAAU,GAAG,QAAQ,GAAG,QAAQ,GAAG,WAAW,GAAG,OAAO,CAAC;AAErE,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AASD,wBAAsB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAgB3E;AA8ID,wBAAsB,KAAK,CAAC,MAAM,CAAC,EAAE,UAAU,GAAG,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CA8BzE;AAED,wBAAsB,mBAAmB,CACvC,GAAG,GAAE,iBAA0C,GAC9C,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAqB1B;AAED,wBAAsB,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC,CAI5C;AAED,wBAAsB,MAAM,CAC1B,GAAG,GAAE,iBAA0C,GAC9C,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAmD1B;AAED,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS,EAAE,CAAC"}
@@ -238,6 +238,17 @@ export async function whoami(env = getEnvironmentConfig()) {
238
238
  console.log();
239
239
  console.log(" " + warning("✗") + " Not logged in");
240
240
  console.log(" " + dim("Run 'veryfront login' to authenticate"));
241
+ // Show provider tokens
242
+ try {
243
+ const { listProviderTokens } = await import("./provider-store.js");
244
+ const providers = await listProviderTokens();
245
+ for (const p of providers) {
246
+ console.log(" " + success("✓") + ` ${p} API key configured`);
247
+ }
248
+ }
249
+ catch {
250
+ // Provider store not available
251
+ }
241
252
  return null;
242
253
  }
243
254
  export { deleteToken, hasToken, readToken, saveToken };
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Provider-namespaced token storage for AI provider API keys.
3
+ *
4
+ * Stores API keys as plaintext with 0600 permissions in
5
+ * ~/.config/veryfront/tokens/<provider>. Same security model
6
+ * as the existing platform token in ~/.config/veryfront/token.
7
+ *
8
+ * @module cli/auth/provider-store
9
+ */
10
+ export type ProviderName = "anthropic" | "openai";
11
+ export interface ProviderCredential {
12
+ apiKey: string;
13
+ validatedAt: string;
14
+ provider: ProviderName;
15
+ }
16
+ export declare function saveProviderToken(provider: ProviderName, credential: ProviderCredential): Promise<void>;
17
+ export declare function readProviderToken(provider: ProviderName): Promise<ProviderCredential | null>;
18
+ export declare function deleteProviderToken(provider: ProviderName): Promise<void>;
19
+ export declare function listProviderTokens(): Promise<ProviderName[]>;
20
+ //# sourceMappingURL=provider-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider-store.d.ts","sourceRoot":"","sources":["../../../src/cli/auth/provider-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAMH,MAAM,MAAM,YAAY,GAAG,WAAW,GAAG,QAAQ,CAAC;AAElD,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,YAAY,CAAC;CACxB;AAUD,wBAAsB,iBAAiB,CACrC,QAAQ,EAAE,YAAY,EACtB,UAAU,EAAE,kBAAkB,GAC7B,OAAO,CAAC,IAAI,CAAC,CAOf;AAED,wBAAsB,iBAAiB,CACrC,QAAQ,EAAE,YAAY,GACrB,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC,CAQpC;AAED,wBAAsB,mBAAmB,CACvC,QAAQ,EAAE,YAAY,GACrB,OAAO,CAAC,IAAI,CAAC,CAOf;AAED,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC,CAgBlE"}
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Provider-namespaced token storage for AI provider API keys.
3
+ *
4
+ * Stores API keys as plaintext with 0600 permissions in
5
+ * ~/.config/veryfront/tokens/<provider>. Same security model
6
+ * as the existing platform token in ~/.config/veryfront/token.
7
+ *
8
+ * @module cli/auth/provider-store
9
+ */
10
+ import { getEnvironmentConfig } from "../../src/config/index.js";
11
+ import { join } from "../../src/platform/compat/path/index.js";
12
+ import { createFileSystem } from "../../src/platform/index.js";
13
+ function getTokenDir() {
14
+ const env = getEnvironmentConfig();
15
+ const configDir = env.xdgConfigHome
16
+ ? join(env.xdgConfigHome, "veryfront")
17
+ : join(env.homeDir, ".config", "veryfront");
18
+ return join(configDir, "tokens");
19
+ }
20
+ export async function saveProviderToken(provider, credential) {
21
+ const fs = createFileSystem();
22
+ const dir = getTokenDir();
23
+ await fs.mkdir(dir, { recursive: true });
24
+ const path = join(dir, provider);
25
+ await fs.writeTextFile(path, JSON.stringify(credential));
26
+ await fs.chmod(path, 0o600);
27
+ }
28
+ export async function readProviderToken(provider) {
29
+ const fs = createFileSystem();
30
+ try {
31
+ const raw = await fs.readTextFile(join(getTokenDir(), provider));
32
+ return JSON.parse(raw);
33
+ }
34
+ catch {
35
+ return null;
36
+ }
37
+ }
38
+ export async function deleteProviderToken(provider) {
39
+ const fs = createFileSystem();
40
+ try {
41
+ await fs.remove(join(getTokenDir(), provider));
42
+ }
43
+ catch {
44
+ // Token doesn't exist — fine
45
+ }
46
+ }
47
+ export async function listProviderTokens() {
48
+ const fs = createFileSystem();
49
+ const providers = [];
50
+ try {
51
+ for await (const entry of fs.readDir(getTokenDir())) {
52
+ if (entry.isFile &&
53
+ (entry.name === "anthropic" || entry.name === "openai")) {
54
+ providers.push(entry.name);
55
+ }
56
+ }
57
+ }
58
+ catch {
59
+ // Directory doesn't exist
60
+ }
61
+ return providers;
62
+ }
@@ -0,0 +1,2 @@
1
+ export declare function loginAnthropic(): Promise<boolean>;
2
+ //# sourceMappingURL=anthropic.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"anthropic.d.ts","sourceRoot":"","sources":["../../../../src/cli/auth/providers/anthropic.ts"],"names":[],"mappings":"AAKA,wBAAsB,cAAc,IAAI,OAAO,CAAC,OAAO,CAAC,CAwCvD"}
@@ -0,0 +1,37 @@
1
+ import * as dntShim from "../../../_dnt.shims.js";
2
+ import { logError, logSuccess, promptPassword } from "../../utils/index.js";
3
+ import { saveProviderToken } from "../provider-store.js";
4
+ import { dim } from "../../ui/colors.js";
5
+ export async function loginAnthropic() {
6
+ console.log(`\n Enter your Anthropic API key.`);
7
+ console.log(` ${dim("Get one at: https://console.anthropic.com/settings/keys")}\n`);
8
+ const apiKey = promptPassword(" API key: ");
9
+ if (!apiKey) {
10
+ logError("No API key provided.");
11
+ return false;
12
+ }
13
+ try {
14
+ const resp = await dntShim.fetch("https://api.anthropic.com/v1/models", {
15
+ headers: {
16
+ "x-api-key": apiKey,
17
+ "anthropic-version": "2023-06-01",
18
+ },
19
+ });
20
+ if (!resp.ok) {
21
+ logError(`Invalid API key (HTTP ${resp.status}). Check your key at console.anthropic.com`);
22
+ return false;
23
+ }
24
+ }
25
+ catch (e) {
26
+ logError(`Failed to validate key: ${e instanceof Error ? e.message : String(e)}`);
27
+ return false;
28
+ }
29
+ const credential = {
30
+ apiKey,
31
+ validatedAt: new Date().toISOString(),
32
+ provider: "anthropic",
33
+ };
34
+ await saveProviderToken("anthropic", credential);
35
+ logSuccess("Anthropic API key configured");
36
+ return true;
37
+ }
@@ -0,0 +1,2 @@
1
+ export declare function loginOpenAI(baseUrl?: string): Promise<boolean>;
2
+ //# sourceMappingURL=openai.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openai.d.ts","sourceRoot":"","sources":["../../../../src/cli/auth/providers/openai.ts"],"names":[],"mappings":"AAKA,wBAAsB,WAAW,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAuCpE"}
@@ -0,0 +1,35 @@
1
+ import * as dntShim from "../../../_dnt.shims.js";
2
+ import { logError, logSuccess, promptPassword } from "../../utils/index.js";
3
+ import { saveProviderToken } from "../provider-store.js";
4
+ import { dim } from "../../ui/colors.js";
5
+ export async function loginOpenAI(baseUrl) {
6
+ console.log(`\n Enter your OpenAI API key.`);
7
+ console.log(` ${dim("Get one at: https://platform.openai.com/api-keys")}\n`);
8
+ const apiKey = promptPassword(" API key: ");
9
+ if (!apiKey) {
10
+ logError("No API key provided.");
11
+ return false;
12
+ }
13
+ const endpoint = baseUrl ?? "https://api.openai.com";
14
+ try {
15
+ const resp = await dntShim.fetch(`${endpoint}/v1/models`, {
16
+ headers: { Authorization: `Bearer ${apiKey}` },
17
+ });
18
+ if (!resp.ok) {
19
+ logError(`Invalid API key (HTTP ${resp.status}). Check your key at platform.openai.com`);
20
+ return false;
21
+ }
22
+ }
23
+ catch (e) {
24
+ logError(`Failed to validate key: ${e instanceof Error ? e.message : String(e)}`);
25
+ return false;
26
+ }
27
+ const credential = {
28
+ apiKey,
29
+ validatedAt: new Date().toISOString(),
30
+ provider: "openai",
31
+ };
32
+ await saveProviderToken("openai", credential);
33
+ logSuccess("OpenAI API key configured");
34
+ return true;
35
+ }
@@ -5,8 +5,13 @@
5
5
  */
6
6
  import type { AuthMethod } from "./login.js";
7
7
  import type { ParsedArgs } from "../shared/types.js";
8
+ import type { ProviderName } from "./provider-store.js";
8
9
  /**
9
10
  * Parse login method from CLI arguments
10
11
  */
11
12
  export declare function parseLoginMethod(args: ParsedArgs): AuthMethod | undefined;
13
+ /**
14
+ * Parse --provider flag from CLI arguments
15
+ */
16
+ export declare function parseProvider(args: ParsedArgs): ProviderName | undefined;
12
17
  //# sourceMappingURL=utils.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/cli/auth/utils.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAErD;;GAEG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,UAAU,GACf,UAAU,GAAG,SAAS,CAMxB"}
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/cli/auth/utils.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAExD;;GAEG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,UAAU,GACf,UAAU,GAAG,SAAS,CAMxB;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,UAAU,GAAG,YAAY,GAAG,SAAS,CAIxE"}
@@ -17,3 +17,12 @@ export function parseLoginMethod(args) {
17
17
  return "token";
18
18
  return undefined;
19
19
  }
20
+ /**
21
+ * Parse --provider flag from CLI arguments
22
+ */
23
+ export function parseProvider(args) {
24
+ const provider = args.provider;
25
+ if (provider === "anthropic" || provider === "openai")
26
+ return provider;
27
+ return undefined;
28
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../../src/cli/router.ts"],"names":[],"mappings":"AA0DA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAmEpD;;;;GAIG;AACH,wBAAsB,YAAY,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CA0FlE"}
1
+ {"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../../src/cli/router.ts"],"names":[],"mappings":"AA0DA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AA0FpD;;;;GAIG;AACH,wBAAsB,YAAY,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CA0FlE"}
package/esm/cli/router.js CHANGED
@@ -76,9 +76,30 @@ const commands = {
76
76
  "deploy": handleDeployCommand,
77
77
  "up": handleUpCommand,
78
78
  "login": async (args) => {
79
+ const { parseProvider } = await import("./auth/utils.js");
80
+ const provider = parseProvider(args);
81
+ if (provider === "anthropic") {
82
+ const { loginAnthropic } = await import("./auth/providers/anthropic.js");
83
+ await loginAnthropic();
84
+ return;
85
+ }
86
+ if (provider === "openai") {
87
+ const { loginOpenAI } = await import("./auth/providers/openai.js");
88
+ await loginOpenAI(args["base-url"]);
89
+ return;
90
+ }
79
91
  await login(parseLoginMethod(args));
80
92
  },
81
- "logout": async () => {
93
+ "logout": async (args) => {
94
+ const { parseProvider } = await import("./auth/utils.js");
95
+ const provider = parseProvider(args);
96
+ if (provider) {
97
+ const { deleteProviderToken } = await import("./auth/provider-store.js");
98
+ await deleteProviderToken(provider);
99
+ const { logSuccess } = await import("./utils/index.js");
100
+ logSuccess(`${provider} API key removed`);
101
+ return;
102
+ }
82
103
  await logout();
83
104
  },
84
105
  "whoami": async () => {
package/esm/deno.js CHANGED
@@ -1,6 +1,6 @@
1
1
  export default {
2
2
  "name": "veryfront",
3
- "version": "0.1.130",
3
+ "version": "0.1.131",
4
4
  "license": "Apache-2.0",
5
5
  "nodeModulesDir": "auto",
6
6
  "exclude": [
@@ -148,13 +148,13 @@ function resolveAgentSkills(agent) {
148
148
  }))
149
149
  .sort((left, right) => left.name.localeCompare(right.name));
150
150
  }
151
- function getRuntimeAgentMetadata(agent) {
151
+ function getRuntimeAgentMetadata(id, agent) {
152
152
  const rawConfig = agent.config;
153
153
  return RuntimeAgentSchema.parse({
154
- id: agent.id,
154
+ id,
155
155
  name: typeof rawConfig.name === "string" && rawConfig.name.trim().length > 0
156
156
  ? rawConfig.name
157
- : agent.id,
157
+ : id,
158
158
  description: typeof rawConfig.description === "string" ? rawConfig.description : null,
159
159
  model: agent.config.model ?? null,
160
160
  version: typeof rawConfig.version === "string" ? rawConfig.version : null,
@@ -164,9 +164,9 @@ function getRuntimeAgentMetadata(agent) {
164
164
  export async function listRuntimeAgents(ctx, deps) {
165
165
  await deps.ensureProjectDiscovery(ctx);
166
166
  const agents = deps.getAllAgentIds()
167
- .map((id) => deps.getAgent(id))
168
- .filter((agent) => Boolean(agent))
169
- .map(getRuntimeAgentMetadata)
167
+ .map((id) => ({ id, agent: deps.getAgent(id) }))
168
+ .filter((entry) => Boolean(entry.agent))
169
+ .map(({ id, agent }) => getRuntimeAgentMetadata(id, agent))
170
170
  .sort((left, right) => left.name.localeCompare(right.name));
171
171
  return RuntimeAgentListResponseSchema.parse({ agents });
172
172
  }
@@ -1 +1 @@
1
- {"version":3,"file":"agent-handler.d.ts","sourceRoot":"","sources":["../../../../src/src/discovery/handlers/agent-handler.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAC;AAElD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAGpD,eAAO,MAAM,YAAY,EAAE,gBAAgB,CAAC,KAAK,CAWhD,CAAC"}
1
+ {"version":3,"file":"agent-handler.d.ts","sourceRoot":"","sources":["../../../../src/src/discovery/handlers/agent-handler.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAC;AAGlD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAGpD,eAAO,MAAM,YAAY,EAAE,gBAAgB,CAAC,KAAK,CAmBhD,CAAC"}
@@ -2,12 +2,21 @@
2
2
  * Agent Discovery Handler
3
3
  */
4
4
  import { registerAgent } from "../../agent/index.js";
5
+ import { agentRegistry } from "../../agent/composition/index.js";
5
6
  import { filenameToId, trackAgentPath } from "../discovery-utils.js";
6
7
  export const agentHandler = {
7
8
  typeName: "agent",
8
9
  validate: (item) => item !== null && typeof item === "object" && typeof item.generate === "function",
9
- getId: (agent, file) => agent.id || filenameToId(file),
10
+ getId: (agent, file) => {
11
+ const configuredId = agent.config.id;
12
+ return typeof configuredId === "string" && configuredId.trim().length > 0
13
+ ? configuredId
14
+ : filenameToId(file);
15
+ },
10
16
  register: (id, agent, file) => {
17
+ if (agent.id !== id) {
18
+ agentRegistry.delete(agent.id);
19
+ }
11
20
  registerAgent(id, agent);
12
21
  trackAgentPath(id, file);
13
22
  return agent;
@@ -6,6 +6,7 @@
6
6
  import type { ClientModuleStrategy } from "./client-module-strategy.ts";
7
7
  import {
8
8
  buildClientModuleUrl,
9
+ type ClientRuntimeHydrationData,
9
10
  getHydrationReactImportSpecifiers,
10
11
  readHydrationData,
11
12
  resolveClientModuleStrategy,
@@ -58,6 +59,18 @@ export function selectHydrationRoot<T extends HydrationRootCandidate>(
58
59
  fallback;
59
60
  }
60
61
 
62
+ interface RSCBootDocument {
63
+ getElementById(id: string): Element | null;
64
+ }
65
+
66
+ export function shouldAttemptRSCTransport(
67
+ doc: RSCBootDocument,
68
+ hydrationData: ClientRuntimeHydrationData | null,
69
+ ): boolean {
70
+ if (hydrationData?.pagePath) return false;
71
+ return !!doc.getElementById(RSC_ROOT_ID);
72
+ }
73
+
61
74
  async function tryStream(q: string): Promise<boolean> {
62
75
  try {
63
76
  const res = await fetch(RSC_PATH_PREFIX + "stream" + q);
@@ -151,8 +164,12 @@ export async function boot(): Promise<void> {
151
164
  console.debug?.("[RSC] Found page component in hydration data:", pagePath);
152
165
  if (await hydratePageComponent(pagePath, clientModuleStrategy)) {
153
166
  console.debug?.("[RSC] Client component hydrated successfully");
154
- return;
155
167
  }
168
+ return;
169
+ }
170
+
171
+ if (!shouldAttemptRSCTransport(document, hydrationData)) {
172
+ return;
156
173
  }
157
174
 
158
175
  if (await tryStream(q)) {
@@ -24,6 +24,8 @@ interface MarkdownHtmlOptions {
24
24
  projectId: string;
25
25
  /** File path of the markdown file. */
26
26
  filePath: string;
27
+ /** CSP nonce for inline scripts. */
28
+ nonce?: string;
27
29
  }
28
30
  /**
29
31
  * Generate a complete HTML document for markdown preview rendering.
@@ -1 +1 @@
1
- {"version":3,"file":"markdown-html-generator.d.ts","sourceRoot":"","sources":["../../../../../src/src/server/handlers/preview/markdown-html-generator.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,KAAK,OAAO,MAAM,2BAA2B,CAAC;AAKrD,oDAAoD;AACpD,UAAU,mBAAmB;IAC3B,wDAAwD;IACxD,OAAO,EAAE,MAAM,CAAC;IAChB,kDAAkD;IAClD,KAAK,EAAE,MAAM,CAAC;IACd,yCAAyC;IACzC,WAAW,EAAE,MAAM,CAAC;IACpB,iDAAiD;IACjD,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC;IACzB,gDAAgD;IAChD,GAAG,EAAE,GAAG,CAAC;IACT,gDAAgD;IAChD,SAAS,EAAE,MAAM,CAAC;IAClB,sCAAsC;IACtC,QAAQ,EAAE,MAAM,CAAC;CAClB;AAuDD;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,mBAAmB,GAAG,MAAM,CA0FzE"}
1
+ {"version":3,"file":"markdown-html-generator.d.ts","sourceRoot":"","sources":["../../../../../src/src/server/handlers/preview/markdown-html-generator.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,KAAK,OAAO,MAAM,2BAA2B,CAAC;AAMrD,oDAAoD;AACpD,UAAU,mBAAmB;IAC3B,wDAAwD;IACxD,OAAO,EAAE,MAAM,CAAC;IAChB,kDAAkD;IAClD,KAAK,EAAE,MAAM,CAAC;IACd,yCAAyC;IACzC,WAAW,EAAE,MAAM,CAAC;IACpB,iDAAiD;IACjD,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC;IACzB,gDAAgD;IAChD,GAAG,EAAE,GAAG,CAAC;IACT,gDAAgD;IAChD,SAAS,EAAE,MAAM,CAAC;IAClB,sCAAsC;IACtC,QAAQ,EAAE,MAAM,CAAC;IACjB,oCAAoC;IACpC,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAyDD;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,mBAAmB,GAAG,MAAM,CA2FzE"}
@@ -1,4 +1,5 @@
1
1
  import { escapeHtml } from "../../../utils/html-escape.js";
2
+ import { buildNonceAttribute } from "../../../html/html-escape.js";
2
3
  /**
3
4
  * Detect the preferred color theme from request parameters and client hints.
4
5
  *
@@ -23,10 +24,11 @@ function detectTheme(req, url) {
23
24
  * Generate the studio bridge `<script>` tag.
24
25
  * Injected only when embedded in Studio (`studio_embed=true`).
25
26
  */
26
- function buildStudioScript(url, projectId, filePath) {
27
+ function buildStudioScript(url, projectId, filePath, nonce) {
27
28
  const studioEmbed = url.searchParams.get("studio_embed") === "true";
28
29
  if (!studioEmbed)
29
30
  return "";
31
+ const nonceAttr = buildNonceAttribute(nonce);
30
32
  const rawQueryProjectId = url.searchParams.get("vf_project_id")?.trim() || "";
31
33
  // Validate query param before using it in bridge config.
32
34
  const queryProjectId = /^[a-zA-Z0-9_-]+$/.test(rawQueryProjectId) ? rawQueryProjectId : "";
@@ -40,8 +42,8 @@ function buildStudioScript(url, projectId, filePath) {
40
42
  };
41
43
  // Escape </script> sequences to prevent XSS breakout from inline JSON
42
44
  const safeJson = JSON.stringify(bridgeConfig).replace(/</g, "\\u003c");
43
- return `<script>window.__VF_BRIDGE_CONFIG__=${safeJson};</script>
44
- <script type="module" src="/_veryfront/studio-bridge.js"></script>`;
45
+ return `<script${nonceAttr}>window.__VF_BRIDGE_CONFIG__=${safeJson};</script>
46
+ <script type="module" src="/_veryfront/studio-bridge.js"${nonceAttr}></script>`;
45
47
  }
46
48
  /**
47
49
  * Generate a complete HTML document for markdown preview rendering.
@@ -51,10 +53,11 @@ function buildStudioScript(url, projectId, filePath) {
51
53
  * studio bridge integration.
52
54
  */
53
55
  export function generateMarkdownHtml(options) {
54
- const { rawHtml, title, description, request, url, projectId, filePath } = options;
56
+ const { rawHtml, title, description, request, url, projectId, filePath, nonce } = options;
55
57
  const theme = detectTheme(request, url);
56
- const studioScript = buildStudioScript(url, projectId, filePath);
58
+ const studioScript = buildStudioScript(url, projectId, filePath, nonce);
57
59
  const themeAttrs = theme ? ` data-theme="${theme}" style="color-scheme: ${theme};"` : "";
60
+ const nonceAttr = buildNonceAttribute(nonce);
58
61
  return `<!DOCTYPE html>
59
62
  <html lang="en"${themeAttrs}>
60
63
  <head>
@@ -75,7 +78,7 @@ export function generateMarkdownHtml(options) {
75
78
 
76
79
  ${studioScript}
77
80
 
78
- <script type="module">
81
+ <script type="module"${nonceAttr}>
79
82
  import mermaid from 'https://esm.sh/mermaid@11.4.1?pin=v135';
80
83
 
81
84
  function getMermaidTheme() {
@@ -135,7 +138,7 @@ export function generateMarkdownHtml(options) {
135
138
  </script>
136
139
 
137
140
  <!-- Preview HMR -->
138
- <script src="/_veryfront/preview-hmr.js"></script>
141
+ <script src="/_veryfront/preview-hmr.js"${nonceAttr}></script>
139
142
  </body>
140
143
  </html>`;
141
144
  }
@@ -1 +1 @@
1
- {"version":3,"file":"markdown-preview.handler.d.ts","sourceRoot":"","sources":["../../../../../src/src/server/handlers/preview/markdown-preview.handler.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,KAAK,OAAO,MAAM,2BAA2B,CAAC;AAGrD,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAmB,aAAa,EAAE,MAAM,aAAa,CAAC;AAgBnG,qBAAa,sBAAuB,SAAQ,WAAW;IACrD,QAAQ,EAAE,eAAe,CAKvB;IAEI,MAAM,CAAC,GAAG,EAAE,OAAO,CAAC,OAAO,EAAE,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC;YAmEjE,cAAc;CAiF7B"}
1
+ {"version":3,"file":"markdown-preview.handler.d.ts","sourceRoot":"","sources":["../../../../../src/src/server/handlers/preview/markdown-preview.handler.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,KAAK,OAAO,MAAM,2BAA2B,CAAC;AAGrD,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAmB,aAAa,EAAE,MAAM,aAAa,CAAC;AAgBnG,qBAAa,sBAAuB,SAAQ,WAAW;IACrD,QAAQ,EAAE,eAAe,CAKvB;IAEI,MAAM,CAAC,GAAG,EAAE,OAAO,CAAC,OAAO,EAAE,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC;YAmEjE,cAAc;CAoF7B"}
@@ -103,6 +103,7 @@ export class MarkdownPreviewHandler extends BaseHandler {
103
103
  return this.continue();
104
104
  }
105
105
  const bundle = await compileMarkdownRuntime("development", ctx.projectDir, body, frontmatter, filePath, "server");
106
+ const responseBuilder = this.createResponseBuilder(ctx);
106
107
  const html = generateMarkdownHtml({
107
108
  rawHtml: bundle.rawHtml || "",
108
109
  title: frontmatter.title != null ? String(frontmatter.title) : filePath,
@@ -111,15 +112,17 @@ export class MarkdownPreviewHandler extends BaseHandler {
111
112
  url,
112
113
  projectId: ctx.projectSlug || ctx.projectId || "markdown-preview",
113
114
  filePath,
115
+ nonce: responseBuilder.nonce,
114
116
  });
115
- const responseBuilder = this.createResponseBuilder(ctx)
117
+ responseBuilder
116
118
  .withCache("no-cache")
117
- .withContentType("text/html; charset=utf-8", html, HTTP_OK);
119
+ .withSecurity(ctx.securityConfig ?? undefined, req);
120
+ const response = responseBuilder.withContentType("text/html; charset=utf-8", html, HTTP_OK);
118
121
  logger.debug("Serving markdown preview", {
119
122
  filePath,
120
123
  htmlLength: html.length,
121
124
  });
122
- return this.respond(responseBuilder);
125
+ return this.respond(response);
123
126
  }
124
127
  catch (error) {
125
128
  logger.error("Error rendering markdown", {
@@ -1 +1 @@
1
- {"version":3,"file":"project-discovery.d.ts","sourceRoot":"","sources":["../../../../../../src/src/server/handlers/request/api/project-discovery.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AA8CrD;;;;;GAKG;AACH,wBAAsB,sBAAsB,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAkE/E"}
1
+ {"version":3,"file":"project-discovery.d.ts","sourceRoot":"","sources":["../../../../../../src/src/server/handlers/request/api/project-discovery.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AA+DrD;;;;;GAKG;AACH,wBAAsB,sBAAsB,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CA8D/E"}
@@ -12,6 +12,21 @@ const logger = serverLogger.component("api-wrapper");
12
12
  * allows retry on failure (the key is deleted if discovery rejects).
13
13
  */
14
14
  const discoveredProjects = new Map();
15
+ function buildDiscoveryConfig(ctx) {
16
+ const ai = ctx.config?.ai;
17
+ const skillDiscoveryEnabled = ai?.skills?.discovery?.enabled ?? true;
18
+ return {
19
+ baseDir: ctx.projectDir,
20
+ toolDirs: ai?.tools?.discovery?.paths ?? ["tools"],
21
+ agentDirs: ai?.agents?.discovery?.paths ?? ["agents"],
22
+ skillDirs: skillDiscoveryEnabled ? (ai?.skills?.discovery?.paths ?? ["skills"]) : [],
23
+ resourceDirs: ["resources"],
24
+ promptDirs: ["prompts"],
25
+ workflowDirs: ["workflows"],
26
+ fsAdapter: ctx.adapter.fs,
27
+ verbose: false,
28
+ };
29
+ }
15
30
  /** Build a discovery cache key that incorporates the release/version. */
16
31
  function discoveryKey(ctx) {
17
32
  const cacheContext = tryGetCacheKeyContext();
@@ -59,11 +74,7 @@ export async function ensureProjectDiscovery(ctx) {
59
74
  clearTranspileCache();
60
75
  agentRegistry.clear();
61
76
  toolRegistry.clear();
62
- const result = await discoverAll({
63
- baseDir: ctx.projectDir,
64
- fsAdapter: ctx.adapter.fs,
65
- verbose: false,
66
- });
77
+ const result = await discoverAll(buildDiscoveryConfig(ctx));
67
78
  const logData = {
68
79
  projectSlug: ctx.projectSlug,
69
80
  releaseId: ctx.releaseId,
@@ -3,4 +3,5 @@ import type { HandlerContext } from "../../types.js";
3
3
  export declare function buildCSP(ctx: HandlerContext): string;
4
4
  export declare function getSecurityHeader(headerName: string, defaultValue: string, ctx: HandlerContext): string;
5
5
  export declare function applySecurityHeaders(headers: dntShim.Headers, ctx: HandlerContext, req?: dntShim.Request): void;
6
+ export declare function applySecurityHeadersWithNonce(headers: dntShim.Headers, ctx: HandlerContext, nonce: string, req?: dntShim.Request): void;
6
7
  //# sourceMappingURL=security-headers.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"security-headers.d.ts","sourceRoot":"","sources":["../../../../../../src/src/server/handlers/request/api/security-headers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,8BAA8B,CAAC;AACxD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAarD,wBAAgB,QAAQ,CAAC,GAAG,EAAE,cAAc,GAAG,MAAM,CAQpD;AAED,wBAAgB,iBAAiB,CAC/B,UAAU,EAAE,MAAM,EAClB,YAAY,EAAE,MAAM,EACpB,GAAG,EAAE,cAAc,GAClB,MAAM,CAER;AAED,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,GAAG,EAAE,cAAc,EAAE,GAAG,CAAC,EAAE,OAAO,CAAC,OAAO,GAAG,IAAI,CAa/G"}
1
+ {"version":3,"file":"security-headers.d.ts","sourceRoot":"","sources":["../../../../../../src/src/server/handlers/request/api/security-headers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,8BAA8B,CAAC;AACxD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAarD,wBAAgB,QAAQ,CAAC,GAAG,EAAE,cAAc,GAAG,MAAM,CAQpD;AAED,wBAAgB,iBAAiB,CAC/B,UAAU,EAAE,MAAM,EAClB,YAAY,EAAE,MAAM,EACpB,GAAG,EAAE,cAAc,GAClB,MAAM,CAER;AAED,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,GAAG,EAAE,cAAc,EAAE,GAAG,CAAC,EAAE,OAAO,CAAC,OAAO,GAAG,IAAI,CAE/G;AAED,wBAAgB,6BAA6B,CAC3C,OAAO,EAAE,OAAO,CAAC,OAAO,EACxB,GAAG,EAAE,cAAc,EACnB,KAAK,EAAE,MAAM,EACb,GAAG,CAAC,EAAE,OAAO,CAAC,OAAO,GACpB,IAAI,CAaN"}
@@ -10,7 +10,10 @@ export function getSecurityHeader(headerName, defaultValue, ctx) {
10
10
  return coreGetSecurityHeader(headerName, defaultValue, ctx.securityConfig, ctx.adapter);
11
11
  }
12
12
  export function applySecurityHeaders(headers, ctx, req) {
13
- coreApplySecurityHeaders(headers, isDev(ctx), generateNonce(), ctx.cspUserHeader ?? null, ctx.securityConfig, ctx.adapter, ctx.parsedDomain?.allowIframeEmbed ?? false);
13
+ applySecurityHeadersWithNonce(headers, ctx, generateNonce(), req);
14
+ }
15
+ export function applySecurityHeadersWithNonce(headers, ctx, nonce, req) {
16
+ coreApplySecurityHeaders(headers, isDev(ctx), nonce, ctx.cspUserHeader ?? null, ctx.securityConfig, ctx.adapter, ctx.parsedDomain?.allowIframeEmbed ?? false);
14
17
  if (req) {
15
18
  applyCsrfCookie(req, headers, ctx.securityConfig?.csrf);
16
19
  }
@@ -1 +1 @@
1
- {"version":3,"file":"openapi-docs.handler.d.ts","sourceRoot":"","sources":["../../../../../src/src/server/handlers/request/openapi-docs.handler.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,KAAK,OAAO,MAAM,2BAA2B,CAAC;AAGrD,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAmB,aAAa,EAAE,MAAM,aAAa,CAAC;AAWnG,qBAAa,kBAAmB,SAAQ,WAAW;IACjD,QAAQ,EAAE,eAAe,CAKvB;cAEiB,YAAY,CAAC,GAAG,EAAE,OAAO,CAAC,OAAO,EAAE,GAAG,EAAE,cAAc,GAAG,OAAO;IAMnF,MAAM,CAAC,GAAG,EAAE,OAAO,CAAC,OAAO,EAAE,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC;IAazE,OAAO,CAAC,gBAAgB;CAsCzB"}
1
+ {"version":3,"file":"openapi-docs.handler.d.ts","sourceRoot":"","sources":["../../../../../src/src/server/handlers/request/openapi-docs.handler.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,KAAK,OAAO,MAAM,2BAA2B,CAAC;AAGrD,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAmB,aAAa,EAAE,MAAM,aAAa,CAAC;AAWnG,qBAAa,kBAAmB,SAAQ,WAAW;IACjD,QAAQ,EAAE,eAAe,CAKvB;cAEiB,YAAY,CAAC,GAAG,EAAE,OAAO,CAAC,OAAO,EAAE,GAAG,EAAE,cAAc,GAAG,OAAO;IAMnF,MAAM,CAAC,GAAG,EAAE,OAAO,CAAC,OAAO,EAAE,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC;IAezE,OAAO,CAAC,gBAAgB;CAwCzB"}
@@ -1,6 +1,6 @@
1
1
  import { BaseHandler } from "../response/base.js";
2
2
  import { HTTP_OK, PRIORITY_HIGH_DEV } from "../../../utils/constants/index.js";
3
- import { escapeHtml } from "../../../html/html-escape.js";
3
+ import { buildNonceAttribute, escapeHtml } from "../../../html/html-escape.js";
4
4
  /** Default paths */
5
5
  const DEFAULT_DOCS_PATH = "/_docs";
6
6
  const DEFAULT_JSON_PATH = "/_openapi.json";
@@ -21,17 +21,20 @@ export class OpenAPIDocsHandler extends BaseHandler {
21
21
  handle(req, ctx) {
22
22
  if (!this.shouldHandle(req, ctx))
23
23
  return Promise.resolve(this.continue());
24
- const html = this.generateDocsPage(ctx);
25
24
  const isDev = !!ctx.isLocalProject;
26
- const response = this.createResponseBuilder(ctx)
25
+ const builder = this.createResponseBuilder(ctx);
26
+ const html = this.generateDocsPage(ctx, builder.nonce);
27
+ const response = builder
27
28
  .withCache(isDev ? "no-cache" : { maxAge: DOCS_CACHE_MAX_AGE_SECONDS, public: true })
29
+ .withSecurity(ctx.securityConfig ?? undefined, req)
28
30
  .withContentType("text/html; charset=utf-8", html, HTTP_OK);
29
31
  return Promise.resolve(this.respond(response));
30
32
  }
31
- generateDocsPage(ctx) {
33
+ generateDocsPage(ctx, nonce) {
32
34
  const specUrl = ctx.config?.openapi?.paths?.json ?? DEFAULT_JSON_PATH;
33
35
  const title = escapeHtml(ctx.config?.openapi?.title ?? "API Documentation");
34
36
  const description = escapeHtml(ctx.config?.openapi?.description ?? "");
37
+ const nonceAttr = buildNonceAttribute(nonce);
35
38
  const configuration = JSON.stringify({
36
39
  theme: "purple",
37
40
  layout: "modern",
@@ -47,7 +50,7 @@ export class OpenAPIDocsHandler extends BaseHandler {
47
50
  <meta name="viewport" content="width=device-width, initial-scale=1"/>
48
51
  <title>${title}</title>
49
52
  ${description ? `<meta name="description" content="${description}"/>` : ""}
50
- <style>
53
+ <style${nonceAttr}>
51
54
  body {
52
55
  margin: 0;
53
56
  padding: 0;
@@ -59,8 +62,9 @@ export class OpenAPIDocsHandler extends BaseHandler {
59
62
  id="api-reference"
60
63
  data-url="${specUrl}"
61
64
  data-configuration='${configuration}'
65
+ ${nonce ? `nonce="${escapeHtml(nonce)}"` : ""}
62
66
  ></script>
63
- <script src="https://cdn.jsdelivr.net/npm/@scalar/api-reference"></script>
67
+ <script src="https://cdn.jsdelivr.net/npm/@scalar/api-reference"${nonceAttr}></script>
64
68
  </body>
65
69
  </html>`;
66
70
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../src/src/server/handlers/request/rsc/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,OAAO,MAAM,8BAA8B,CAAC;AAGxD,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,KAAK,EACV,cAAc,EACd,eAAe,EAEf,aAAa,EACd,MAAM,gBAAgB,CAAC;AAQxB,qBAAa,UAAW,SAAQ,WAAW;IACzC,QAAQ,EAAE,eAAe,CAIvB;IAEF,MAAM,CAAC,GAAG,EAAE,OAAO,CAAC,OAAO,EAAE,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC;CAmD1E"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../src/src/server/handlers/request/rsc/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,OAAO,MAAM,8BAA8B,CAAC;AAGxD,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,KAAK,EACV,cAAc,EACd,eAAe,EAEf,aAAa,EACd,MAAM,gBAAgB,CAAC;AASxB,qBAAa,UAAW,SAAQ,WAAW;IACzC,QAAQ,EAAE,eAAe,CAIvB;IAEF,MAAM,CAAC,GAAG,EAAE,OAAO,CAAC,OAAO,EAAE,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC;CAqD1E"}