@executor-js/plugin-keychain 0.0.1-beta.3 → 0.0.1-beta.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# @executor
|
|
1
|
+
# @executor/plugin-keychain
|
|
2
2
|
|
|
3
3
|
OS-keychain-backed secret store for the executor. Reads and writes secrets to:
|
|
4
4
|
|
|
@@ -8,21 +8,21 @@ OS-keychain-backed secret store for the executor. Reads and writes secrets to:
|
|
|
8
8
|
|
|
9
9
|
Secrets are encrypted at rest by the operating system and never touch your project's filesystem.
|
|
10
10
|
|
|
11
|
-
Pairs with [`@executor
|
|
11
|
+
Pairs with [`@executor/sdk`](https://www.npmjs.com/package/@executor/sdk) (promise-based) or [`@executor/core`](https://www.npmjs.com/package/@executor/core) (Effect-based).
|
|
12
12
|
|
|
13
13
|
## Install
|
|
14
14
|
|
|
15
15
|
```sh
|
|
16
|
-
bun add @executor
|
|
16
|
+
bun add @executor/sdk @executor/plugin-keychain
|
|
17
17
|
# or
|
|
18
|
-
npm install @executor
|
|
18
|
+
npm install @executor/sdk @executor/plugin-keychain
|
|
19
19
|
```
|
|
20
20
|
|
|
21
21
|
## Usage
|
|
22
22
|
|
|
23
23
|
```ts
|
|
24
|
-
import { createExecutor } from "@executor
|
|
25
|
-
import { keychainPlugin } from "@executor
|
|
24
|
+
import { createExecutor } from "@executor/sdk";
|
|
25
|
+
import { keychainPlugin } from "@executor/plugin-keychain";
|
|
26
26
|
|
|
27
27
|
const executor = await createExecutor({
|
|
28
28
|
scope: { name: "my-app" },
|
|
@@ -42,14 +42,14 @@ if (executor.keychain.isSupported) {
|
|
|
42
42
|
}
|
|
43
43
|
```
|
|
44
44
|
|
|
45
|
-
Secrets written through this plugin are available to every other plugin that resolves secrets by ID — so you can store a token once and use it across `@executor
|
|
45
|
+
Secrets written through this plugin are available to every other plugin that resolves secrets by ID — so you can store a token once and use it across `@executor/plugin-openapi`, `@executor/plugin-graphql`, etc. via `{ secretId, prefix }` headers.
|
|
46
46
|
|
|
47
47
|
## Effect entry point
|
|
48
48
|
|
|
49
|
-
If you're using `@executor
|
|
49
|
+
If you're using `@executor/core` directly, import from the `/core` subpath:
|
|
50
50
|
|
|
51
51
|
```ts
|
|
52
|
-
import { keychainPlugin } from "@executor
|
|
52
|
+
import { keychainPlugin } from "@executor/plugin-keychain/core";
|
|
53
53
|
```
|
|
54
54
|
|
|
55
55
|
## Status
|
|
@@ -8,14 +8,8 @@ import {
|
|
|
8
8
|
import { Effect } from "effect";
|
|
9
9
|
|
|
10
10
|
// src/errors.ts
|
|
11
|
-
import {
|
|
12
|
-
var KeychainError = class extends
|
|
13
|
-
"KeychainError",
|
|
14
|
-
{
|
|
15
|
-
message: Schema.String,
|
|
16
|
-
cause: Schema.optional(Schema.Unknown)
|
|
17
|
-
}
|
|
18
|
-
) {
|
|
11
|
+
import { Data } from "effect";
|
|
12
|
+
var KeychainError = class extends Data.TaggedError("KeychainError") {
|
|
19
13
|
};
|
|
20
14
|
|
|
21
15
|
// src/keyring.ts
|
|
@@ -121,4 +115,4 @@ export {
|
|
|
121
115
|
makeKeychainProvider,
|
|
122
116
|
keychainPlugin
|
|
123
117
|
};
|
|
124
|
-
//# sourceMappingURL=chunk-
|
|
118
|
+
//# sourceMappingURL=chunk-AWJ4XIQJ.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/keyring.ts","../src/errors.ts","../src/provider.ts"],"sourcesContent":["import { Effect } from \"effect\";\n\nimport {\n definePlugin,\n type SecretId,\n type ExecutorPlugin,\n} from \"@executor/sdk/core\";\n\nimport { displayName, isSupportedPlatform, resolveServiceName } from \"./keyring\";\nimport { getPassword } from \"./keyring\";\nimport { makeKeychainProvider } from \"./provider\";\n\n// ---------------------------------------------------------------------------\n// Re-exports\n// ---------------------------------------------------------------------------\n\nexport { KeychainError } from \"./errors\";\nexport { makeKeychainProvider } from \"./provider\";\nexport { isSupportedPlatform, displayName } from \"./keyring\";\n\n// ---------------------------------------------------------------------------\n// Plugin config\n// ---------------------------------------------------------------------------\n\nexport interface KeychainPluginConfig {\n /** Override the keychain service name (default: \"executor\") */\n readonly serviceName?: string;\n}\n\n// ---------------------------------------------------------------------------\n// Plugin extension — public API on executor.keychain\n// ---------------------------------------------------------------------------\n\nexport interface KeychainExtension {\n /** Human-readable name for the keychain on this platform */\n readonly displayName: string;\n\n /** Whether the current platform supports system keychain */\n readonly isSupported: boolean;\n\n /** Check if a secret exists in the system keychain */\n readonly has: (secretId: SecretId) => Effect.Effect<boolean>;\n}\n\n// ---------------------------------------------------------------------------\n// Plugin definition\n// ---------------------------------------------------------------------------\n\nconst PLUGIN_KEY = \"keychain\";\n\nexport const keychainPlugin = (\n config?: KeychainPluginConfig,\n): ExecutorPlugin<typeof PLUGIN_KEY, KeychainExtension> =>\n definePlugin({\n key: PLUGIN_KEY,\n init: (ctx) =>\n Effect.gen(function* () {\n // Scope the service name to the current scope so each folder gets its own keychain entries\n const baseServiceName = resolveServiceName(config?.serviceName);\n const serviceName = `${baseServiceName}/${ctx.scope.id}`;\n\n yield* ctx.secrets.addProvider(makeKeychainProvider(serviceName));\n\n const extension: KeychainExtension = {\n displayName: displayName(),\n isSupported: isSupportedPlatform(),\n\n has: (secretId) =>\n getPassword(serviceName, secretId).pipe(\n Effect.map((v) => v !== null),\n Effect.orElseSucceed(() => false),\n ),\n };\n\n return { extension };\n }),\n });\n","import { Effect } from \"effect\";\n\nimport { KeychainError } from \"./errors\";\n\n// ---------------------------------------------------------------------------\n// Constants\n// ---------------------------------------------------------------------------\n\nconst DEFAULT_SERVICE_NAME = \"executor\";\nconst SERVICE_NAME_ENV = \"EXECUTOR_KEYCHAIN_SERVICE_NAME\";\n\n// ---------------------------------------------------------------------------\n// Platform helpers\n// ---------------------------------------------------------------------------\n\nexport const isSupportedPlatform = () =>\n process.platform === \"darwin\" ||\n process.platform === \"linux\" ||\n process.platform === \"win32\";\n\nexport const displayName = () =>\n process.platform === \"darwin\"\n ? \"macOS Keychain\"\n : process.platform === \"win32\"\n ? \"Windows Credential Manager\"\n : \"Desktop Keyring\";\n\nexport const resolveServiceName = (explicit?: string): string =>\n explicit?.trim() || process.env[SERVICE_NAME_ENV]?.trim() || DEFAULT_SERVICE_NAME;\n\n// ---------------------------------------------------------------------------\n// Lazy-load @napi-rs/keyring (native module)\n// ---------------------------------------------------------------------------\n\ntype EntryConstructor = (typeof import(\"@napi-rs/keyring\"))[\"Entry\"];\n\nlet entryCtorPromise: Promise<EntryConstructor> | null = null;\n\nconst loadEntry = (): Effect.Effect<EntryConstructor, KeychainError> =>\n Effect.tryPromise({\n try: async () => {\n if (!isSupportedPlatform()) {\n throw new Error(`unsupported platform '${process.platform}'`);\n }\n entryCtorPromise ??= import(\"@napi-rs/keyring\").then(({ Entry }) => Entry);\n return await entryCtorPromise;\n },\n catch: (cause) =>\n new KeychainError({\n message: `Failed loading native keyring: ${cause instanceof Error ? cause.message : String(cause)}`,\n cause,\n }),\n });\n\nconst createEntry = (serviceName: string, account: string) =>\n Effect.flatMap(loadEntry(), (Entry) =>\n Effect.try({\n try: () => new Entry(serviceName, account),\n catch: (cause) =>\n new KeychainError({\n message: `Failed creating keyring entry: ${cause instanceof Error ? cause.message : String(cause)}`,\n cause,\n }),\n }),\n );\n\n// ---------------------------------------------------------------------------\n// Low-level keychain operations\n// ---------------------------------------------------------------------------\n\nexport const getPassword = (\n serviceName: string,\n account: string,\n): Effect.Effect<string | null, KeychainError> =>\n Effect.flatMap(createEntry(serviceName, account), (entry) =>\n Effect.try({\n try: () => entry.getPassword(),\n catch: () => new KeychainError({ message: `Failed reading secret for account '${account}'` }),\n }),\n );\n\nexport const setPassword = (\n serviceName: string,\n account: string,\n value: string,\n): Effect.Effect<void, KeychainError> =>\n Effect.flatMap(createEntry(serviceName, account), (entry) =>\n Effect.try({\n try: () => entry.setPassword(value),\n catch: (cause) =>\n new KeychainError({\n message: `Failed writing secret: ${cause instanceof Error ? cause.message : String(cause)}`,\n cause,\n }),\n }).pipe(Effect.asVoid),\n );\n\nexport const deletePassword = (\n serviceName: string,\n account: string,\n): Effect.Effect<boolean, KeychainError> =>\n Effect.flatMap(createEntry(serviceName, account), (entry) =>\n Effect.try({\n try: () => {\n entry.deletePassword();\n return true;\n },\n catch: () => new KeychainError({ message: `Failed deleting secret for account '${account}'` }),\n }),\n );\n","import { Data } from \"effect\";\n\nexport class KeychainError extends Data.TaggedError(\"KeychainError\")<{\n readonly message: string;\n readonly cause?: unknown;\n}> {}\n","import { Effect } from \"effect\";\n\nimport type { SecretProvider } from \"@executor/sdk/core\";\n\nimport { getPassword, setPassword, deletePassword } from \"./keyring\";\n\n// ---------------------------------------------------------------------------\n// SecretProvider adapter — bridges keyring into SDK resolution chain\n// ---------------------------------------------------------------------------\n\nexport const makeKeychainProvider = (serviceName: string): SecretProvider => ({\n key: \"keychain\",\n writable: true,\n get: (secretId) =>\n getPassword(serviceName, secretId).pipe(\n Effect.orElseSucceed(() => null),\n ),\n set: (secretId, value) =>\n setPassword(serviceName, secretId, value).pipe(\n Effect.orElseSucceed(() => undefined),\n ),\n delete: (secretId) =>\n deletePassword(serviceName, secretId).pipe(\n Effect.orElseSucceed(() => false),\n ),\n // Keychain doesn't support enumerating — you need to know the account name\n list: undefined,\n});\n"],"mappings":"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","names":["Effect","Effect","Effect","Effect"]}
|
package/dist/core.js
CHANGED
package/dist/errors.d.ts
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
message:
|
|
6
|
-
cause
|
|
7
|
-
}
|
|
8
|
-
export declare class KeychainError extends KeychainError_base {
|
|
1
|
+
declare const KeychainError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
|
|
2
|
+
readonly _tag: "KeychainError";
|
|
3
|
+
} & Readonly<A>;
|
|
4
|
+
export declare class KeychainError extends KeychainError_base<{
|
|
5
|
+
readonly message: string;
|
|
6
|
+
readonly cause?: unknown;
|
|
7
|
+
}> {
|
|
9
8
|
}
|
|
10
9
|
export {};
|
package/dist/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@executor-js/plugin-keychain",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.0.1-beta.
|
|
4
|
+
"version": "0.0.1-beta.4",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
36
|
"@napi-rs/keyring": "^1.2.0",
|
|
37
|
-
"@executor-js/sdk": "0.0.1-beta.
|
|
37
|
+
"@executor-js/sdk": "0.0.1-beta.4",
|
|
38
38
|
"effect": "^3.21.0"
|
|
39
39
|
},
|
|
40
40
|
"devDependencies": {
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/keyring.ts","../src/errors.ts","../src/provider.ts"],"sourcesContent":["import { Effect } from \"effect\";\n\nimport {\n definePlugin,\n type SecretId,\n type ExecutorPlugin,\n} from \"@executor-js/sdk/core\";\n\nimport { displayName, isSupportedPlatform, resolveServiceName } from \"./keyring\";\nimport { getPassword } from \"./keyring\";\nimport { makeKeychainProvider } from \"./provider\";\n\n// ---------------------------------------------------------------------------\n// Re-exports\n// ---------------------------------------------------------------------------\n\nexport { KeychainError } from \"./errors\";\nexport { makeKeychainProvider } from \"./provider\";\nexport { isSupportedPlatform, displayName } from \"./keyring\";\n\n// ---------------------------------------------------------------------------\n// Plugin config\n// ---------------------------------------------------------------------------\n\nexport interface KeychainPluginConfig {\n /** Override the keychain service name (default: \"executor\") */\n readonly serviceName?: string;\n}\n\n// ---------------------------------------------------------------------------\n// Plugin extension — public API on executor.keychain\n// ---------------------------------------------------------------------------\n\nexport interface KeychainExtension {\n /** Human-readable name for the keychain on this platform */\n readonly displayName: string;\n\n /** Whether the current platform supports system keychain */\n readonly isSupported: boolean;\n\n /** Check if a secret exists in the system keychain */\n readonly has: (secretId: SecretId) => Effect.Effect<boolean>;\n}\n\n// ---------------------------------------------------------------------------\n// Plugin definition\n// ---------------------------------------------------------------------------\n\nconst PLUGIN_KEY = \"keychain\";\n\nexport const keychainPlugin = (\n config?: KeychainPluginConfig,\n): ExecutorPlugin<typeof PLUGIN_KEY, KeychainExtension> =>\n definePlugin({\n key: PLUGIN_KEY,\n init: (ctx) =>\n Effect.gen(function* () {\n // Scope the service name to the current scope so each folder gets its own keychain entries\n const baseServiceName = resolveServiceName(config?.serviceName);\n const serviceName = `${baseServiceName}/${ctx.scope.id}`;\n\n yield* ctx.secrets.addProvider(makeKeychainProvider(serviceName));\n\n const extension: KeychainExtension = {\n displayName: displayName(),\n isSupported: isSupportedPlatform(),\n\n has: (secretId) =>\n getPassword(serviceName, secretId).pipe(\n Effect.map((v) => v !== null),\n Effect.orElseSucceed(() => false),\n ),\n };\n\n return { extension };\n }),\n });\n","import { Effect } from \"effect\";\n\nimport { KeychainError } from \"./errors\";\n\n// ---------------------------------------------------------------------------\n// Constants\n// ---------------------------------------------------------------------------\n\nconst DEFAULT_SERVICE_NAME = \"executor\";\nconst SERVICE_NAME_ENV = \"EXECUTOR_KEYCHAIN_SERVICE_NAME\";\n\n// ---------------------------------------------------------------------------\n// Platform helpers\n// ---------------------------------------------------------------------------\n\nexport const isSupportedPlatform = () =>\n process.platform === \"darwin\" ||\n process.platform === \"linux\" ||\n process.platform === \"win32\";\n\nexport const displayName = () =>\n process.platform === \"darwin\"\n ? \"macOS Keychain\"\n : process.platform === \"win32\"\n ? \"Windows Credential Manager\"\n : \"Desktop Keyring\";\n\nexport const resolveServiceName = (explicit?: string): string =>\n explicit?.trim() || process.env[SERVICE_NAME_ENV]?.trim() || DEFAULT_SERVICE_NAME;\n\n// ---------------------------------------------------------------------------\n// Lazy-load @napi-rs/keyring (native module)\n// ---------------------------------------------------------------------------\n\ntype EntryConstructor = (typeof import(\"@napi-rs/keyring\"))[\"Entry\"];\n\nlet entryCtorPromise: Promise<EntryConstructor> | null = null;\n\nconst loadEntry = (): Effect.Effect<EntryConstructor, KeychainError> =>\n Effect.tryPromise({\n try: async () => {\n if (!isSupportedPlatform()) {\n throw new Error(`unsupported platform '${process.platform}'`);\n }\n entryCtorPromise ??= import(\"@napi-rs/keyring\").then(({ Entry }) => Entry);\n return await entryCtorPromise;\n },\n catch: (cause) =>\n new KeychainError({\n message: `Failed loading native keyring: ${cause instanceof Error ? cause.message : String(cause)}`,\n cause,\n }),\n });\n\nconst createEntry = (serviceName: string, account: string) =>\n Effect.flatMap(loadEntry(), (Entry) =>\n Effect.try({\n try: () => new Entry(serviceName, account),\n catch: (cause) =>\n new KeychainError({\n message: `Failed creating keyring entry: ${cause instanceof Error ? cause.message : String(cause)}`,\n cause,\n }),\n }),\n );\n\n// ---------------------------------------------------------------------------\n// Low-level keychain operations\n// ---------------------------------------------------------------------------\n\nexport const getPassword = (\n serviceName: string,\n account: string,\n): Effect.Effect<string | null, KeychainError> =>\n Effect.flatMap(createEntry(serviceName, account), (entry) =>\n Effect.try({\n try: () => entry.getPassword(),\n catch: () => new KeychainError({ message: `Failed reading secret for account '${account}'` }),\n }),\n );\n\nexport const setPassword = (\n serviceName: string,\n account: string,\n value: string,\n): Effect.Effect<void, KeychainError> =>\n Effect.flatMap(createEntry(serviceName, account), (entry) =>\n Effect.try({\n try: () => entry.setPassword(value),\n catch: (cause) =>\n new KeychainError({\n message: `Failed writing secret: ${cause instanceof Error ? cause.message : String(cause)}`,\n cause,\n }),\n }).pipe(Effect.asVoid),\n );\n\nexport const deletePassword = (\n serviceName: string,\n account: string,\n): Effect.Effect<boolean, KeychainError> =>\n Effect.flatMap(createEntry(serviceName, account), (entry) =>\n Effect.try({\n try: () => {\n entry.deletePassword();\n return true;\n },\n catch: () => new KeychainError({ message: `Failed deleting secret for account '${account}'` }),\n }),\n );\n","import { Schema } from \"effect\";\n\nexport class KeychainError extends Schema.TaggedError<KeychainError>()(\n \"KeychainError\",\n {\n message: Schema.String,\n cause: Schema.optional(Schema.Unknown),\n },\n) {}\n","import { Effect } from \"effect\";\n\nimport type { SecretProvider } from \"@executor-js/sdk/core\";\n\nimport { getPassword, setPassword, deletePassword } from \"./keyring\";\n\n// ---------------------------------------------------------------------------\n// SecretProvider adapter — bridges keyring into SDK resolution chain\n// ---------------------------------------------------------------------------\n\nexport const makeKeychainProvider = (serviceName: string): SecretProvider => ({\n key: \"keychain\",\n writable: true,\n get: (secretId) =>\n getPassword(serviceName, secretId).pipe(\n Effect.orElseSucceed(() => null),\n ),\n set: (secretId, value) =>\n setPassword(serviceName, secretId, value).pipe(\n Effect.orElseSucceed(() => undefined),\n ),\n delete: (secretId) =>\n deletePassword(serviceName, secretId).pipe(\n Effect.orElseSucceed(() => false),\n ),\n // Keychain doesn't support enumerating — you need to know the account name\n list: undefined,\n});\n"],"mappings":"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","names":["Effect","Effect","Effect","Effect"]}
|