toolcraft-openapi 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (157) hide show
  1. package/README.md +64 -0
  2. package/dist/api-command.d.ts +7 -0
  3. package/dist/api-command.js +4 -0
  4. package/dist/auth/bearer-token-auth.d.ts +8 -0
  5. package/dist/auth/bearer-token-auth.js +216 -0
  6. package/dist/auth/types.d.ts +9 -0
  7. package/dist/auth/types.js +1 -0
  8. package/dist/bin/generate.d.ts +40 -0
  9. package/dist/bin/generate.js +248 -0
  10. package/dist/define-client.d.ts +20 -0
  11. package/dist/define-client.js +148 -0
  12. package/dist/generate.d.ts +210 -0
  13. package/dist/generate.js +1131 -0
  14. package/dist/group-by-noun.d.ts +6 -0
  15. package/dist/group-by-noun.js +17 -0
  16. package/dist/http.d.ts +26 -0
  17. package/dist/http.js +123 -0
  18. package/dist/index.d.ts +12 -0
  19. package/dist/index.js +6 -0
  20. package/dist/interpreter.d.ts +6 -0
  21. package/dist/interpreter.js +289 -0
  22. package/dist/lock.d.ts +14 -0
  23. package/dist/lock.js +48 -0
  24. package/dist/naming.d.ts +24 -0
  25. package/dist/naming.js +218 -0
  26. package/dist/request-shape.d.ts +15 -0
  27. package/dist/request-shape.js +5 -0
  28. package/dist/runtime.d.ts +13 -0
  29. package/dist/runtime.js +94 -0
  30. package/dist/spec-source.d.ts +11 -0
  31. package/dist/spec-source.js +63 -0
  32. package/node_modules/@poe-code/design-system/dist/acp/components.d.ts +11 -0
  33. package/node_modules/@poe-code/design-system/dist/acp/components.js +121 -0
  34. package/node_modules/@poe-code/design-system/dist/acp/index.d.ts +3 -0
  35. package/node_modules/@poe-code/design-system/dist/acp/index.js +2 -0
  36. package/node_modules/@poe-code/design-system/dist/acp/writer.d.ts +13 -0
  37. package/node_modules/@poe-code/design-system/dist/acp/writer.js +21 -0
  38. package/node_modules/@poe-code/design-system/dist/components/command-errors.d.ts +16 -0
  39. package/node_modules/@poe-code/design-system/dist/components/command-errors.js +22 -0
  40. package/node_modules/@poe-code/design-system/dist/components/help-formatter.d.ts +20 -0
  41. package/node_modules/@poe-code/design-system/dist/components/help-formatter.js +27 -0
  42. package/node_modules/@poe-code/design-system/dist/components/index.d.ts +10 -0
  43. package/node_modules/@poe-code/design-system/dist/components/index.js +7 -0
  44. package/node_modules/@poe-code/design-system/dist/components/logger.d.ts +11 -0
  45. package/node_modules/@poe-code/design-system/dist/components/logger.js +60 -0
  46. package/node_modules/@poe-code/design-system/dist/components/symbols.d.ts +12 -0
  47. package/node_modules/@poe-code/design-system/dist/components/symbols.js +71 -0
  48. package/node_modules/@poe-code/design-system/dist/components/table.d.ts +13 -0
  49. package/node_modules/@poe-code/design-system/dist/components/table.js +74 -0
  50. package/node_modules/@poe-code/design-system/dist/components/text.d.ts +14 -0
  51. package/node_modules/@poe-code/design-system/dist/components/text.js +104 -0
  52. package/node_modules/@poe-code/design-system/dist/dashboard/ansi.d.ts +18 -0
  53. package/node_modules/@poe-code/design-system/dist/dashboard/ansi.js +298 -0
  54. package/node_modules/@poe-code/design-system/dist/dashboard/buffer.d.ts +25 -0
  55. package/node_modules/@poe-code/design-system/dist/dashboard/buffer.js +189 -0
  56. package/node_modules/@poe-code/design-system/dist/dashboard/components/border.d.ts +9 -0
  57. package/node_modules/@poe-code/design-system/dist/dashboard/components/border.js +123 -0
  58. package/node_modules/@poe-code/design-system/dist/dashboard/components/footer.d.ts +8 -0
  59. package/node_modules/@poe-code/design-system/dist/dashboard/components/footer.js +57 -0
  60. package/node_modules/@poe-code/design-system/dist/dashboard/components/output-pane.d.ts +12 -0
  61. package/node_modules/@poe-code/design-system/dist/dashboard/components/output-pane.js +254 -0
  62. package/node_modules/@poe-code/design-system/dist/dashboard/components/stats-pane.d.ts +7 -0
  63. package/node_modules/@poe-code/design-system/dist/dashboard/components/stats-pane.js +121 -0
  64. package/node_modules/@poe-code/design-system/dist/dashboard/dashboard.d.ts +20 -0
  65. package/node_modules/@poe-code/design-system/dist/dashboard/dashboard.js +167 -0
  66. package/node_modules/@poe-code/design-system/dist/dashboard/demo.d.ts +13 -0
  67. package/node_modules/@poe-code/design-system/dist/dashboard/demo.js +145 -0
  68. package/node_modules/@poe-code/design-system/dist/dashboard/index.d.ts +8 -0
  69. package/node_modules/@poe-code/design-system/dist/dashboard/index.js +4 -0
  70. package/node_modules/@poe-code/design-system/dist/dashboard/keymap.d.ts +3 -0
  71. package/node_modules/@poe-code/design-system/dist/dashboard/keymap.js +99 -0
  72. package/node_modules/@poe-code/design-system/dist/dashboard/layout.d.ts +25 -0
  73. package/node_modules/@poe-code/design-system/dist/dashboard/layout.js +79 -0
  74. package/node_modules/@poe-code/design-system/dist/dashboard/should-use-dashboard.d.ts +10 -0
  75. package/node_modules/@poe-code/design-system/dist/dashboard/should-use-dashboard.js +7 -0
  76. package/node_modules/@poe-code/design-system/dist/dashboard/snapshot.d.ts +10 -0
  77. package/node_modules/@poe-code/design-system/dist/dashboard/snapshot.js +68 -0
  78. package/node_modules/@poe-code/design-system/dist/dashboard/store.d.ts +8 -0
  79. package/node_modules/@poe-code/design-system/dist/dashboard/store.js +51 -0
  80. package/node_modules/@poe-code/design-system/dist/dashboard/terminal.d.ts +37 -0
  81. package/node_modules/@poe-code/design-system/dist/dashboard/terminal.js +233 -0
  82. package/node_modules/@poe-code/design-system/dist/dashboard/types.d.ts +36 -0
  83. package/node_modules/@poe-code/design-system/dist/dashboard/types.js +1 -0
  84. package/node_modules/@poe-code/design-system/dist/index.d.ts +33 -0
  85. package/node_modules/@poe-code/design-system/dist/index.js +31 -0
  86. package/node_modules/@poe-code/design-system/dist/internal/output-format.d.ts +6 -0
  87. package/node_modules/@poe-code/design-system/dist/internal/output-format.js +22 -0
  88. package/node_modules/@poe-code/design-system/dist/internal/strip-ansi.d.ts +1 -0
  89. package/node_modules/@poe-code/design-system/dist/internal/strip-ansi.js +3 -0
  90. package/node_modules/@poe-code/design-system/dist/internal/theme-detect.d.ts +11 -0
  91. package/node_modules/@poe-code/design-system/dist/internal/theme-detect.js +49 -0
  92. package/node_modules/@poe-code/design-system/dist/prompts/index.d.ts +66 -0
  93. package/node_modules/@poe-code/design-system/dist/prompts/index.js +132 -0
  94. package/node_modules/@poe-code/design-system/dist/prompts/primitives/cancel.d.ts +2 -0
  95. package/node_modules/@poe-code/design-system/dist/prompts/primitives/cancel.js +9 -0
  96. package/node_modules/@poe-code/design-system/dist/prompts/primitives/intro.d.ts +1 -0
  97. package/node_modules/@poe-code/design-system/dist/prompts/primitives/intro.js +15 -0
  98. package/node_modules/@poe-code/design-system/dist/prompts/primitives/log.d.ts +18 -0
  99. package/node_modules/@poe-code/design-system/dist/prompts/primitives/log.js +101 -0
  100. package/node_modules/@poe-code/design-system/dist/prompts/primitives/note.d.ts +1 -0
  101. package/node_modules/@poe-code/design-system/dist/prompts/primitives/note.js +39 -0
  102. package/node_modules/@poe-code/design-system/dist/prompts/primitives/outro.d.ts +1 -0
  103. package/node_modules/@poe-code/design-system/dist/prompts/primitives/outro.js +16 -0
  104. package/node_modules/@poe-code/design-system/dist/prompts/primitives/spinner.d.ts +6 -0
  105. package/node_modules/@poe-code/design-system/dist/prompts/primitives/spinner.js +74 -0
  106. package/node_modules/@poe-code/design-system/dist/prompts/theme.d.ts +11 -0
  107. package/node_modules/@poe-code/design-system/dist/prompts/theme.js +12 -0
  108. package/node_modules/@poe-code/design-system/dist/static/index.d.ts +4 -0
  109. package/node_modules/@poe-code/design-system/dist/static/index.js +2 -0
  110. package/node_modules/@poe-code/design-system/dist/static/menu.d.ts +11 -0
  111. package/node_modules/@poe-code/design-system/dist/static/menu.js +36 -0
  112. package/node_modules/@poe-code/design-system/dist/static/spinner.d.ts +14 -0
  113. package/node_modules/@poe-code/design-system/dist/static/spinner.js +46 -0
  114. package/node_modules/@poe-code/design-system/dist/terminal-markdown/ast.d.ts +92 -0
  115. package/node_modules/@poe-code/design-system/dist/terminal-markdown/ast.js +1 -0
  116. package/node_modules/@poe-code/design-system/dist/terminal-markdown/demo-content.d.ts +2 -0
  117. package/node_modules/@poe-code/design-system/dist/terminal-markdown/demo-content.js +139 -0
  118. package/node_modules/@poe-code/design-system/dist/terminal-markdown/index.d.ts +6 -0
  119. package/node_modules/@poe-code/design-system/dist/terminal-markdown/index.js +8 -0
  120. package/node_modules/@poe-code/design-system/dist/terminal-markdown/parser/block.d.ts +7 -0
  121. package/node_modules/@poe-code/design-system/dist/terminal-markdown/parser/block.js +1495 -0
  122. package/node_modules/@poe-code/design-system/dist/terminal-markdown/parser/frontmatter.d.ts +8 -0
  123. package/node_modules/@poe-code/design-system/dist/terminal-markdown/parser/frontmatter.js +412 -0
  124. package/node_modules/@poe-code/design-system/dist/terminal-markdown/parser/inline.d.ts +10 -0
  125. package/node_modules/@poe-code/design-system/dist/terminal-markdown/parser/inline.js +1166 -0
  126. package/node_modules/@poe-code/design-system/dist/terminal-markdown/parser.d.ts +5 -0
  127. package/node_modules/@poe-code/design-system/dist/terminal-markdown/parser.js +42 -0
  128. package/node_modules/@poe-code/design-system/dist/terminal-markdown/renderer.d.ts +6 -0
  129. package/node_modules/@poe-code/design-system/dist/terminal-markdown/renderer.js +572 -0
  130. package/node_modules/@poe-code/design-system/dist/terminal-markdown/testing/theme-render-fixture.d.ts +1 -0
  131. package/node_modules/@poe-code/design-system/dist/terminal-markdown/testing/theme-render-fixture.js +27 -0
  132. package/node_modules/@poe-code/design-system/dist/tokens/colors.d.ts +35 -0
  133. package/node_modules/@poe-code/design-system/dist/tokens/colors.js +34 -0
  134. package/node_modules/@poe-code/design-system/dist/tokens/index.d.ts +4 -0
  135. package/node_modules/@poe-code/design-system/dist/tokens/index.js +4 -0
  136. package/node_modules/@poe-code/design-system/dist/tokens/spacing.d.ts +6 -0
  137. package/node_modules/@poe-code/design-system/dist/tokens/spacing.js +6 -0
  138. package/node_modules/@poe-code/design-system/dist/tokens/typography.d.ts +7 -0
  139. package/node_modules/@poe-code/design-system/dist/tokens/typography.js +8 -0
  140. package/node_modules/@poe-code/design-system/dist/tokens/widths.d.ts +5 -0
  141. package/node_modules/@poe-code/design-system/dist/tokens/widths.js +5 -0
  142. package/node_modules/@poe-code/design-system/package.json +25 -0
  143. package/node_modules/auth-store/README.md +47 -0
  144. package/node_modules/auth-store/dist/create-secret-store.d.ts +2 -0
  145. package/node_modules/auth-store/dist/create-secret-store.js +35 -0
  146. package/node_modules/auth-store/dist/encrypted-file-store.d.ts +39 -0
  147. package/node_modules/auth-store/dist/encrypted-file-store.js +156 -0
  148. package/node_modules/auth-store/dist/index.d.ts +7 -0
  149. package/node_modules/auth-store/dist/index.js +4 -0
  150. package/node_modules/auth-store/dist/keychain-store.d.ts +22 -0
  151. package/node_modules/auth-store/dist/keychain-store.js +111 -0
  152. package/node_modules/auth-store/dist/provider-store.d.ts +10 -0
  153. package/node_modules/auth-store/dist/provider-store.js +28 -0
  154. package/node_modules/auth-store/dist/types.d.ts +20 -0
  155. package/node_modules/auth-store/dist/types.js +1 -0
  156. package/node_modules/auth-store/package.json +25 -0
  157. package/package.json +48 -0
@@ -0,0 +1,34 @@
1
+ import chalk from "chalk";
2
+ export const brand = "#a200ff";
3
+ export const dark = {
4
+ header: (text) => chalk.magentaBright.bold(text),
5
+ divider: (text) => chalk.dim(text),
6
+ prompt: (text) => chalk.cyan(text),
7
+ number: (text) => chalk.cyanBright(text),
8
+ intro: (text) => chalk.bgMagenta.white(` Poe - ${text} `),
9
+ resolvedSymbol: chalk.magenta("◇"),
10
+ errorSymbol: chalk.red("■"),
11
+ accent: (text) => chalk.cyan(text),
12
+ muted: (text) => chalk.dim(text),
13
+ success: (text) => chalk.green(text),
14
+ warning: (text) => chalk.yellow(text),
15
+ error: (text) => chalk.red(text),
16
+ info: (text) => chalk.magenta(text),
17
+ badge: (text) => chalk.bgYellow.black(` ${text} `)
18
+ };
19
+ export const light = {
20
+ header: (text) => chalk.hex("#a200ff").bold(text),
21
+ divider: (text) => chalk.hex("#666666")(text),
22
+ prompt: (text) => chalk.hex("#006699").bold(text),
23
+ number: (text) => chalk.hex("#0077cc").bold(text),
24
+ intro: (text) => chalk.bgHex("#a200ff").white(` Poe - ${text} `),
25
+ resolvedSymbol: chalk.hex("#a200ff")("◇"),
26
+ errorSymbol: chalk.hex("#cc0000")("■"),
27
+ accent: (text) => chalk.hex("#006699").bold(text),
28
+ muted: (text) => chalk.hex("#666666")(text),
29
+ success: (text) => chalk.hex("#008800")(text),
30
+ warning: (text) => chalk.hex("#cc6600")(text),
31
+ error: (text) => chalk.hex("#cc0000")(text),
32
+ info: (text) => chalk.hex("#a200ff")(text),
33
+ badge: (text) => chalk.bgHex("#cc6600").white(` ${text} `)
34
+ };
@@ -0,0 +1,4 @@
1
+ export * from "./colors.js";
2
+ export { spacing } from "./spacing.js";
3
+ export { typography } from "./typography.js";
4
+ export { widths } from "./widths.js";
@@ -0,0 +1,4 @@
1
+ export * from "./colors.js";
2
+ export { spacing } from "./spacing.js";
3
+ export { typography } from "./typography.js";
4
+ export { widths } from "./widths.js";
@@ -0,0 +1,6 @@
1
+ export declare const spacing: {
2
+ readonly sm: 1;
3
+ readonly md: 2;
4
+ readonly lg: 4;
5
+ readonly xl: 8;
6
+ };
@@ -0,0 +1,6 @@
1
+ export const spacing = {
2
+ sm: 1,
3
+ md: 2,
4
+ lg: 4,
5
+ xl: 8
6
+ };
@@ -0,0 +1,7 @@
1
+ export declare const typography: {
2
+ readonly bold: (text: string) => string;
3
+ readonly dim: (text: string) => string;
4
+ readonly italic: (text: string) => string;
5
+ readonly underline: (text: string) => string;
6
+ readonly strikethrough: (text: string) => string;
7
+ };
@@ -0,0 +1,8 @@
1
+ import chalk from "chalk";
2
+ export const typography = {
3
+ bold: (text) => chalk.bold(text),
4
+ dim: (text) => chalk.dim(text),
5
+ italic: (text) => chalk.italic(text),
6
+ underline: (text) => chalk.underline(text),
7
+ strikethrough: (text) => chalk.strikethrough(text)
8
+ };
@@ -0,0 +1,5 @@
1
+ export declare const widths: {
2
+ readonly header: 60;
3
+ readonly helpColumn: 24;
4
+ readonly maxLine: 80;
5
+ };
@@ -0,0 +1,5 @@
1
+ export const widths = {
2
+ header: 60,
3
+ helpColumn: 24,
4
+ maxLine: 80
5
+ };
@@ -0,0 +1,25 @@
1
+ {
2
+ "name": "@poe-code/design-system",
3
+ "version": "0.0.1",
4
+ "type": "module",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "scripts": {
8
+ "build": "tsc",
9
+ "lint": "cd ../.. && eslint packages/design-system --ext ts && tsc -p packages/design-system/tsconfig.json --noEmit",
10
+ "test": "cd ../.. && vitest run $(rg --files packages/design-system/src -g '*.test.ts' | sort | tr '\\n' ' ')",
11
+ "demo": "tsx scripts/demo.ts",
12
+ "generate:docs": "tsx scripts/generate-docs.ts all",
13
+ "generate:design-docs:markdown": "tsx scripts/generate-docs.ts markdown",
14
+ "generate:design-docs:json": "tsx scripts/generate-docs.ts json",
15
+ "generate:design-docs:all": "tsx scripts/generate-docs.ts all"
16
+ },
17
+ "files": [
18
+ "dist"
19
+ ],
20
+ "peerDependencies": {
21
+ "@clack/prompts": "^1.0.0",
22
+ "chalk": "^5.3.0",
23
+ "console-table-printer": "^2.15.0"
24
+ }
25
+ }
@@ -0,0 +1,47 @@
1
+ # auth-store
2
+
3
+ Generic encrypted secret storage with platform-aware backends.
4
+
5
+ ## Usage
6
+
7
+ ```ts
8
+ import { createSecretStore } from "auth-store";
9
+
10
+ const { store, backend } = createSecretStore({
11
+ backendEnvVar: "MY_AUTH_BACKEND",
12
+ fileStore: {
13
+ salt: "my-app:encrypted-store:v1",
14
+ defaultDirectory: ".my-app",
15
+ defaultFileName: "credentials.enc"
16
+ },
17
+ keychainStore: {
18
+ service: "my-app",
19
+ account: "api-key"
20
+ }
21
+ });
22
+
23
+ await store.set("secret-value");
24
+ const value = await store.get(); // "secret-value"
25
+ await store.delete();
26
+ ```
27
+
28
+ ## Backends
29
+
30
+ | `backendEnvVar` value | Platform | Backend |
31
+ | --------------------- | -------- | -------------- |
32
+ | _(unset)_ | any | Encrypted file |
33
+ | `file` | any | Encrypted file |
34
+ | `keychain` | macOS | macOS Keychain |
35
+ | `keychain` | other | Error |
36
+
37
+ ### Encrypted file
38
+
39
+ - AES-256-GCM with machine-derived key (hostname + username via scrypt)
40
+ - Configurable salt, directory, and file name
41
+ - File permissions: `0600`
42
+ - Random IV per write
43
+
44
+ ### macOS Keychain
45
+
46
+ - Uses the `security` CLI (`add-generic-password`, `find-generic-password`, `delete-generic-password`)
47
+ - Configurable service and account names
@@ -0,0 +1,2 @@
1
+ import type { CreateSecretStoreInput, CreateSecretStoreResult } from "./types.js";
2
+ export declare function createSecretStore(input: CreateSecretStoreInput): CreateSecretStoreResult;
@@ -0,0 +1,35 @@
1
+ import { EncryptedFileStore } from "./encrypted-file-store.js";
2
+ import { KeychainStore } from "./keychain-store.js";
3
+ const DEFAULT_BACKEND_ENV_VAR = "AUTH_BACKEND";
4
+ const MACOS_PLATFORM = "darwin";
5
+ const storeFactories = {
6
+ file: (input) => {
7
+ if (!input.fileStore) {
8
+ throw new Error("fileStore configuration is required for file backend");
9
+ }
10
+ return new EncryptedFileStore(input.fileStore);
11
+ },
12
+ keychain: (input) => {
13
+ if (!input.keychainStore) {
14
+ throw new Error("keychainStore configuration is required for keychain backend");
15
+ }
16
+ return new KeychainStore(input.keychainStore);
17
+ }
18
+ };
19
+ export function createSecretStore(input) {
20
+ const backend = resolveBackend(input);
21
+ const platform = input.platform ?? process.platform;
22
+ if (backend === "keychain" && platform !== MACOS_PLATFORM) {
23
+ throw new Error(`Keychain backend is only supported on macOS. Current platform: ${platform}`);
24
+ }
25
+ const store = storeFactories[backend](input);
26
+ return { backend, store };
27
+ }
28
+ function resolveBackend(input) {
29
+ const envVar = input.backendEnvVar ?? DEFAULT_BACKEND_ENV_VAR;
30
+ const configuredBackend = input.backend ?? input.env?.[envVar] ?? process.env[envVar];
31
+ if (configuredBackend === "keychain") {
32
+ return "keychain";
33
+ }
34
+ return "file";
35
+ }
@@ -0,0 +1,39 @@
1
+ import type { SecretStore } from "./types.js";
2
+ export interface MachineIdentity {
3
+ hostname: string;
4
+ username: string;
5
+ }
6
+ export interface EncryptedFileStoreFileSystem {
7
+ readFile(path: string, encoding: BufferEncoding): Promise<string>;
8
+ writeFile(path: string, data: string | NodeJS.ArrayBufferView, options?: {
9
+ encoding?: BufferEncoding;
10
+ }): Promise<void>;
11
+ mkdir(path: string, options?: {
12
+ recursive?: boolean;
13
+ }): Promise<void | string | undefined>;
14
+ unlink(path: string): Promise<void>;
15
+ chmod(path: string, mode: number): Promise<void>;
16
+ }
17
+ export interface EncryptedFileStoreInput {
18
+ fs?: EncryptedFileStoreFileSystem;
19
+ filePath?: string;
20
+ salt: string;
21
+ defaultDirectory?: string;
22
+ defaultFileName?: string;
23
+ getMachineIdentity?: () => MachineIdentity | Promise<MachineIdentity>;
24
+ getHomeDirectory?: () => string;
25
+ getRandomBytes?: (size: number) => Buffer;
26
+ }
27
+ export declare class EncryptedFileStore implements SecretStore {
28
+ private readonly fs;
29
+ private readonly filePath;
30
+ private readonly salt;
31
+ private readonly getMachineIdentity;
32
+ private readonly getRandomBytes;
33
+ private keyPromise;
34
+ constructor(input: EncryptedFileStoreInput);
35
+ get(): Promise<string | null>;
36
+ set(value: string): Promise<void>;
37
+ delete(): Promise<void>;
38
+ private getEncryptionKey;
39
+ }
@@ -0,0 +1,156 @@
1
+ import { createCipheriv, createDecipheriv, randomBytes, scrypt } from "node:crypto";
2
+ import { promises as fs } from "node:fs";
3
+ import { homedir, hostname, userInfo } from "node:os";
4
+ import path from "node:path";
5
+ const derivedKeyCache = new Map();
6
+ const ENCRYPTION_ALGORITHM = "aes-256-gcm";
7
+ const ENCRYPTION_VERSION = 1;
8
+ const ENCRYPTION_KEY_BYTES = 32;
9
+ const ENCRYPTION_IV_BYTES = 12;
10
+ const ENCRYPTION_AUTH_TAG_BYTES = 16;
11
+ const ENCRYPTION_FILE_MODE = 0o600;
12
+ export class EncryptedFileStore {
13
+ fs;
14
+ filePath;
15
+ salt;
16
+ getMachineIdentity;
17
+ getRandomBytes;
18
+ keyPromise = null;
19
+ constructor(input) {
20
+ this.fs = input.fs ?? fs;
21
+ this.salt = input.salt;
22
+ this.filePath = input.filePath ?? path.join((input.getHomeDirectory ?? homedir)(), input.defaultDirectory ?? ".auth-store", input.defaultFileName ?? "credentials.enc");
23
+ this.getMachineIdentity = input.getMachineIdentity ?? defaultMachineIdentity;
24
+ this.getRandomBytes = input.getRandomBytes ?? randomBytes;
25
+ }
26
+ async get() {
27
+ let rawDocument;
28
+ try {
29
+ rawDocument = await this.fs.readFile(this.filePath, "utf8");
30
+ }
31
+ catch (error) {
32
+ if (isNotFoundError(error)) {
33
+ return null;
34
+ }
35
+ throw error;
36
+ }
37
+ const document = parseEncryptedDocument(rawDocument);
38
+ if (!document) {
39
+ return null;
40
+ }
41
+ const key = await this.getEncryptionKey();
42
+ try {
43
+ const iv = Buffer.from(document.iv, "base64");
44
+ const authTag = Buffer.from(document.authTag, "base64");
45
+ const ciphertext = Buffer.from(document.ciphertext, "base64");
46
+ if (iv.byteLength !== ENCRYPTION_IV_BYTES ||
47
+ authTag.byteLength !== ENCRYPTION_AUTH_TAG_BYTES) {
48
+ return null;
49
+ }
50
+ const decipher = createDecipheriv(ENCRYPTION_ALGORITHM, key, iv);
51
+ decipher.setAuthTag(authTag);
52
+ const plaintext = Buffer.concat([decipher.update(ciphertext), decipher.final()]);
53
+ return plaintext.toString("utf8");
54
+ }
55
+ catch {
56
+ return null;
57
+ }
58
+ }
59
+ async set(value) {
60
+ const key = await this.getEncryptionKey();
61
+ const iv = this.getRandomBytes(ENCRYPTION_IV_BYTES);
62
+ const cipher = createCipheriv(ENCRYPTION_ALGORITHM, key, iv);
63
+ const ciphertext = Buffer.concat([
64
+ cipher.update(value, "utf8"),
65
+ cipher.final()
66
+ ]);
67
+ const authTag = cipher.getAuthTag();
68
+ const document = {
69
+ version: ENCRYPTION_VERSION,
70
+ iv: iv.toString("base64"),
71
+ authTag: authTag.toString("base64"),
72
+ ciphertext: ciphertext.toString("base64")
73
+ };
74
+ await this.fs.mkdir(path.dirname(this.filePath), { recursive: true });
75
+ await this.fs.writeFile(this.filePath, JSON.stringify(document), {
76
+ encoding: "utf8"
77
+ });
78
+ await this.fs.chmod(this.filePath, ENCRYPTION_FILE_MODE);
79
+ }
80
+ async delete() {
81
+ try {
82
+ await this.fs.unlink(this.filePath);
83
+ }
84
+ catch (error) {
85
+ if (!isNotFoundError(error)) {
86
+ throw error;
87
+ }
88
+ }
89
+ }
90
+ getEncryptionKey() {
91
+ if (!this.keyPromise) {
92
+ this.keyPromise = deriveEncryptionKey(this.getMachineIdentity, this.salt);
93
+ }
94
+ return this.keyPromise;
95
+ }
96
+ }
97
+ function defaultMachineIdentity() {
98
+ return {
99
+ hostname: hostname(),
100
+ username: userInfo().username
101
+ };
102
+ }
103
+ async function deriveEncryptionKey(getMachineIdentity, salt) {
104
+ const machineIdentity = await getMachineIdentity();
105
+ const secret = `${machineIdentity.hostname}:${machineIdentity.username}`;
106
+ const cacheKey = `${secret}:${salt}`;
107
+ const cached = derivedKeyCache.get(cacheKey);
108
+ if (cached) {
109
+ return cached;
110
+ }
111
+ const keyPromise = new Promise((resolve, reject) => {
112
+ scrypt(secret, salt, ENCRYPTION_KEY_BYTES, (error, derivedKey) => {
113
+ if (error) {
114
+ reject(error);
115
+ return;
116
+ }
117
+ resolve(Buffer.from(derivedKey));
118
+ });
119
+ });
120
+ derivedKeyCache.set(cacheKey, keyPromise);
121
+ return keyPromise;
122
+ }
123
+ function parseEncryptedDocument(raw) {
124
+ try {
125
+ const parsed = JSON.parse(raw);
126
+ if (!isRecord(parsed)) {
127
+ return null;
128
+ }
129
+ if (parsed.version !== ENCRYPTION_VERSION) {
130
+ return null;
131
+ }
132
+ if (typeof parsed.iv !== "string" ||
133
+ typeof parsed.authTag !== "string" ||
134
+ typeof parsed.ciphertext !== "string") {
135
+ return null;
136
+ }
137
+ return {
138
+ version: parsed.version,
139
+ iv: parsed.iv,
140
+ authTag: parsed.authTag,
141
+ ciphertext: parsed.ciphertext
142
+ };
143
+ }
144
+ catch {
145
+ return null;
146
+ }
147
+ }
148
+ function isRecord(value) {
149
+ return Boolean(value && typeof value === "object" && !Array.isArray(value));
150
+ }
151
+ function isNotFoundError(error) {
152
+ return Boolean(error &&
153
+ typeof error === "object" &&
154
+ "code" in error &&
155
+ error.code === "ENOENT");
156
+ }
@@ -0,0 +1,7 @@
1
+ export { createSecretStore } from "./create-secret-store.js";
2
+ export { EncryptedFileStore } from "./encrypted-file-store.js";
3
+ export { KeychainStore } from "./keychain-store.js";
4
+ export { key, MigratingSecretStore } from "./provider-store.js";
5
+ export type { SecretStore, StoreBackend, CreateSecretStoreInput, CreateSecretStoreResult } from "./types.js";
6
+ export type { MachineIdentity, EncryptedFileStoreInput, EncryptedFileStoreFileSystem } from "./encrypted-file-store.js";
7
+ export type { KeychainStoreInput, KeychainCommandRunner, KeychainCommandResult } from "./keychain-store.js";
@@ -0,0 +1,4 @@
1
+ export { createSecretStore } from "./create-secret-store.js";
2
+ export { EncryptedFileStore } from "./encrypted-file-store.js";
3
+ export { KeychainStore } from "./keychain-store.js";
4
+ export { key, MigratingSecretStore } from "./provider-store.js";
@@ -0,0 +1,22 @@
1
+ import type { SecretStore } from "./types.js";
2
+ export interface KeychainCommandResult {
3
+ stdout: string;
4
+ stderr: string;
5
+ exitCode: number;
6
+ }
7
+ export type KeychainCommandRunner = (command: string, args: string[]) => Promise<KeychainCommandResult>;
8
+ export interface KeychainStoreInput {
9
+ runCommand?: KeychainCommandRunner;
10
+ service: string;
11
+ account: string;
12
+ }
13
+ export declare class KeychainStore implements SecretStore {
14
+ private readonly runCommand;
15
+ private readonly service;
16
+ private readonly account;
17
+ constructor(input: KeychainStoreInput);
18
+ get(): Promise<string | null>;
19
+ set(value: string): Promise<void>;
20
+ delete(): Promise<void>;
21
+ private executeSecurityCommand;
22
+ }
@@ -0,0 +1,111 @@
1
+ import { spawn } from "node:child_process";
2
+ const SECURITY_CLI = "security";
3
+ const KEYCHAIN_ITEM_NOT_FOUND_EXIT_CODE = 44;
4
+ export class KeychainStore {
5
+ runCommand;
6
+ service;
7
+ account;
8
+ constructor(input) {
9
+ this.runCommand = input.runCommand ?? runSecurityCommand;
10
+ this.service = input.service;
11
+ this.account = input.account;
12
+ }
13
+ async get() {
14
+ const result = await this.executeSecurityCommand(["find-generic-password", "-s", this.service, "-a", this.account, "-w"], "read secret from macOS Keychain");
15
+ if (result.exitCode === 0) {
16
+ return stripTrailingLineBreak(result.stdout);
17
+ }
18
+ if (isKeychainEntryNotFound(result)) {
19
+ return null;
20
+ }
21
+ throw createSecurityCliFailure("read secret from macOS Keychain", result);
22
+ }
23
+ async set(value) {
24
+ const result = await this.executeSecurityCommand([
25
+ "add-generic-password",
26
+ "-s",
27
+ this.service,
28
+ "-a",
29
+ this.account,
30
+ "-w",
31
+ value,
32
+ "-U"
33
+ ], "store secret in macOS Keychain");
34
+ if (result.exitCode !== 0) {
35
+ throw createSecurityCliFailure("store secret in macOS Keychain", result);
36
+ }
37
+ }
38
+ async delete() {
39
+ const result = await this.executeSecurityCommand(["delete-generic-password", "-s", this.service, "-a", this.account], "delete secret from macOS Keychain");
40
+ if (result.exitCode === 0 || isKeychainEntryNotFound(result)) {
41
+ return;
42
+ }
43
+ throw createSecurityCliFailure("delete secret from macOS Keychain", result);
44
+ }
45
+ async executeSecurityCommand(args, operation) {
46
+ try {
47
+ return await this.runCommand(SECURITY_CLI, args);
48
+ }
49
+ catch (error) {
50
+ const message = error instanceof Error ? error.message : String(error);
51
+ throw new Error(`Failed to ${operation}: ${message}`);
52
+ }
53
+ }
54
+ }
55
+ function runSecurityCommand(command, args) {
56
+ return new Promise((resolve) => {
57
+ const child = spawn(command, args, {
58
+ stdio: ["ignore", "pipe", "pipe"]
59
+ });
60
+ let stdout = "";
61
+ let stderr = "";
62
+ child.stdout?.setEncoding("utf8");
63
+ child.stdout?.on("data", (chunk) => {
64
+ stdout += chunk.toString();
65
+ });
66
+ child.stderr?.setEncoding("utf8");
67
+ child.stderr?.on("data", (chunk) => {
68
+ stderr += chunk.toString();
69
+ });
70
+ child.on("error", (error) => {
71
+ const message = error instanceof Error ? error.message : String(error ?? "Unknown error");
72
+ resolve({
73
+ stdout,
74
+ stderr: stderr ? `${stderr}${message}` : message,
75
+ exitCode: 127
76
+ });
77
+ });
78
+ child.on("close", (code) => {
79
+ resolve({
80
+ stdout,
81
+ stderr,
82
+ exitCode: code ?? 0
83
+ });
84
+ });
85
+ });
86
+ }
87
+ function stripTrailingLineBreak(value) {
88
+ if (value.endsWith("\r\n")) {
89
+ return value.slice(0, -2);
90
+ }
91
+ if (value.endsWith("\n") || value.endsWith("\r")) {
92
+ return value.slice(0, -1);
93
+ }
94
+ return value;
95
+ }
96
+ function isKeychainEntryNotFound(result) {
97
+ if (result.exitCode === KEYCHAIN_ITEM_NOT_FOUND_EXIT_CODE) {
98
+ return true;
99
+ }
100
+ const output = `${result.stderr}\n${result.stdout}`.toLowerCase();
101
+ return (output.includes("could not be found") ||
102
+ output.includes("item not found") ||
103
+ output.includes("errsecitemnotfound"));
104
+ }
105
+ function createSecurityCliFailure(operation, result) {
106
+ const details = result.stderr.trim() || result.stdout.trim();
107
+ if (details) {
108
+ return new Error(`Failed to ${operation}: security exited with code ${result.exitCode}: ${details}`);
109
+ }
110
+ return new Error(`Failed to ${operation}: security exited with code ${result.exitCode}`);
111
+ }
@@ -0,0 +1,10 @@
1
+ import type { SecretStore } from "./types.js";
2
+ export declare function key(providerId: string): string;
3
+ export declare class MigratingSecretStore implements SecretStore {
4
+ private readonly store;
5
+ private readonly legacyStore;
6
+ constructor(store: SecretStore, legacyStore?: SecretStore | null);
7
+ get(): Promise<string | null>;
8
+ set(value: string): Promise<void>;
9
+ delete(): Promise<void>;
10
+ }
@@ -0,0 +1,28 @@
1
+ export function key(providerId) {
2
+ return `provider:${providerId}`;
3
+ }
4
+ export class MigratingSecretStore {
5
+ store;
6
+ legacyStore;
7
+ constructor(store, legacyStore = null) {
8
+ this.store = store;
9
+ this.legacyStore = legacyStore;
10
+ }
11
+ async get() {
12
+ const value = await this.store.get();
13
+ if (value !== null || !this.legacyStore) {
14
+ return value;
15
+ }
16
+ const legacyValue = await this.legacyStore.get();
17
+ if (legacyValue !== null) {
18
+ await this.store.set(legacyValue);
19
+ }
20
+ return legacyValue;
21
+ }
22
+ async set(value) {
23
+ return this.store.set(value);
24
+ }
25
+ async delete() {
26
+ return this.store.delete();
27
+ }
28
+ }
@@ -0,0 +1,20 @@
1
+ import type { EncryptedFileStoreInput } from "./encrypted-file-store.js";
2
+ import type { KeychainStoreInput } from "./keychain-store.js";
3
+ export interface SecretStore {
4
+ get(): Promise<string | null>;
5
+ set(value: string): Promise<void>;
6
+ delete(): Promise<void>;
7
+ }
8
+ export type StoreBackend = "file" | "keychain";
9
+ export interface CreateSecretStoreInput {
10
+ backend?: StoreBackend;
11
+ env?: NodeJS.ProcessEnv;
12
+ platform?: NodeJS.Platform;
13
+ backendEnvVar?: string;
14
+ fileStore?: EncryptedFileStoreInput;
15
+ keychainStore?: KeychainStoreInput;
16
+ }
17
+ export interface CreateSecretStoreResult {
18
+ store: SecretStore;
19
+ backend: StoreBackend;
20
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,25 @@
1
+ {
2
+ "name": "auth-store",
3
+ "version": "0.0.1",
4
+ "type": "module",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "exports": {
8
+ ".": {
9
+ "types": "./dist/index.d.ts",
10
+ "import": "./dist/index.js"
11
+ }
12
+ },
13
+ "scripts": {
14
+ "build": "tsc"
15
+ },
16
+ "dependencies": {},
17
+ "files": [
18
+ "dist"
19
+ ],
20
+ "repository": {
21
+ "type": "git",
22
+ "url": "git+https://github.com/poe-platform/poe-code.git",
23
+ "directory": "packages/auth-store"
24
+ }
25
+ }