@executor-js/plugin-file-secrets 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,22 +1,22 @@
1
- # @executor-js/plugin-file-secrets
1
+ # @executor/plugin-file-secrets
2
2
 
3
3
  File-backed secret store for the executor. Persists secrets to a single JSON file at an XDG-compliant path so they survive between process restarts — useful for local development, CLIs, and scripts where a system keychain isn't available.
4
4
 
5
- Pairs with [`@executor-js/sdk`](https://www.npmjs.com/package/@executor-js/sdk) (promise-based) or [`@executor-js/core`](https://www.npmjs.com/package/@executor-js/core) (Effect-based).
5
+ 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).
6
6
 
7
7
  ## Install
8
8
 
9
9
  ```sh
10
- bun add @executor-js/sdk @executor-js/plugin-file-secrets
10
+ bun add @executor/sdk @executor/plugin-file-secrets
11
11
  # or
12
- npm install @executor-js/sdk @executor-js/plugin-file-secrets
12
+ npm install @executor/sdk @executor/plugin-file-secrets
13
13
  ```
14
14
 
15
15
  ## Usage
16
16
 
17
17
  ```ts
18
- import { createExecutor } from "@executor-js/sdk";
19
- import { fileSecretsPlugin } from "@executor-js/plugin-file-secrets";
18
+ import { createExecutor } from "@executor/sdk";
19
+ import { fileSecretsPlugin } from "@executor/plugin-file-secrets";
20
20
 
21
21
  const executor = await createExecutor({
22
22
  scope: { name: "my-app" },
@@ -38,19 +38,19 @@ const value = await executor.secrets.resolve("api-key");
38
38
  console.log("Secret file:", executor.fileSecrets.filePath);
39
39
  ```
40
40
 
41
- Secrets written through `executor.secrets.set(...)` become available to every other plugin that resolves them, so you can (for example) store a GitHub token here and have `@executor-js/plugin-openapi` or `@executor-js/plugin-graphql` pick it up via `{ secretId, prefix }` headers.
41
+ Secrets written through `executor.secrets.set(...)` become available to every other plugin that resolves them, so you can (for example) store a GitHub token here and have `@executor/plugin-openapi` or `@executor/plugin-graphql` pick it up via `{ secretId, prefix }` headers.
42
42
 
43
43
  ## Effect entry point
44
44
 
45
- If you're using `@executor-js/core` directly, import from the `/core` subpath:
45
+ If you're using `@executor/core` directly, import from the `/core` subpath:
46
46
 
47
47
  ```ts
48
- import { fileSecretsPlugin } from "@executor-js/plugin-file-secrets/core";
48
+ import { fileSecretsPlugin } from "@executor/plugin-file-secrets/core";
49
49
  ```
50
50
 
51
51
  ## Security note
52
52
 
53
- Secrets are stored unencrypted in a plain JSON file. Use [`@executor-js/plugin-keychain`](https://www.npmjs.com/package/@executor-js/plugin-keychain) for OS-keychain-backed storage, or [`@executor-js/plugin-onepassword`](https://www.npmjs.com/package/@executor-js/plugin-onepassword) for 1Password-backed storage when you need encryption at rest.
53
+ Secrets are stored unencrypted in a plain JSON file. Use [`@executor/plugin-keychain`](https://www.npmjs.com/package/@executor/plugin-keychain) for OS-keychain-backed storage, or [`@executor/plugin-onepassword`](https://www.npmjs.com/package/@executor/plugin-onepassword) for 1Password-backed storage when you need encryption at rest.
54
54
 
55
55
  ## Status
56
56
 
@@ -84,4 +84,4 @@ var fileSecretsPlugin = (config) => definePlugin({
84
84
  export {
85
85
  fileSecretsPlugin
86
86
  };
87
- //# sourceMappingURL=chunk-GAKDI75V.js.map
87
+ //# sourceMappingURL=chunk-QCGUSGBY.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["import { Effect, Schema } from \"effect\";\nimport {\n definePlugin,\n type ExecutorPlugin,\n type SecretProvider,\n} from \"@executor/sdk/core\";\nimport * as fs from \"node:fs\";\nimport * as path from \"node:path\";\n\n// ---------------------------------------------------------------------------\n// XDG data dir resolution\n// ---------------------------------------------------------------------------\n\nconst APP_NAME = \"executor\";\n\nconst xdgDataHome = (): string =>\n process.env.XDG_DATA_HOME?.trim() ||\n path.join(\n process.env.HOME || process.env.USERPROFILE || \"~\",\n \".local\",\n \"share\",\n );\n\nconst authDir = (overrideDir?: string): string =>\n overrideDir ?? path.join(xdgDataHome(), APP_NAME);\n\nconst authFilePath = (overrideDir?: string): string =>\n path.join(authDir(overrideDir), \"auth.json\");\n\n// ---------------------------------------------------------------------------\n// Schema for the auth file\n//\n// Top-level keys are scope IDs, values are { secretId: secretValue } maps.\n// { \"web-a1b2c3d4\": { \"github-token\": \"ghp_xxx\" } }\n// ---------------------------------------------------------------------------\n\nconst ScopedAuthFile = Schema.Record({\n key: Schema.String,\n value: Schema.Record({ key: Schema.String, value: Schema.String }),\n});\nconst decodeScopedAuthFile = Schema.decodeUnknownSync(ScopedAuthFile);\n\n// ---------------------------------------------------------------------------\n// File I/O with restricted permissions\n// ---------------------------------------------------------------------------\n\nconst readFullFile = (\n filePath: string,\n): Record<string, Record<string, string>> => {\n try {\n if (!fs.existsSync(filePath)) return {};\n const raw = fs.readFileSync(filePath, \"utf-8\");\n return decodeScopedAuthFile(JSON.parse(raw));\n } catch {\n return {};\n }\n};\n\nconst readScopeSecrets = (\n filePath: string,\n scopeId: string,\n): Record<string, string> => readFullFile(filePath)[scopeId] ?? {};\n\nconst writeScopeSecrets = (\n filePath: string,\n scopeId: string,\n secrets: Record<string, string>,\n): void => {\n const dir = path.dirname(filePath);\n if (!fs.existsSync(dir)) {\n fs.mkdirSync(dir, { recursive: true, mode: 0o700 });\n }\n const full = readFullFile(filePath);\n if (Object.keys(secrets).length === 0) {\n delete full[scopeId];\n } else {\n full[scopeId] = secrets;\n }\n const tmp = `${filePath}.tmp`;\n fs.writeFileSync(tmp, JSON.stringify(full, null, 2), { mode: 0o600 });\n fs.renameSync(tmp, filePath);\n};\n\n// ---------------------------------------------------------------------------\n// Plugin config\n// ---------------------------------------------------------------------------\n\nexport interface FileSecretsPluginConfig {\n /** Override the directory for auth.json (default: XDG data dir) */\n readonly directory?: string;\n}\n\n// ---------------------------------------------------------------------------\n// Plugin extension — public API on executor.fileSecrets\n// ---------------------------------------------------------------------------\n\nexport interface FileSecretsExtension {\n /** Path to the auth file */\n readonly filePath: string;\n}\n\n// ---------------------------------------------------------------------------\n// Provider factory (internal)\n// ---------------------------------------------------------------------------\n\nconst makeScopedProvider = (\n filePath: string,\n scopeId: string,\n): SecretProvider => ({\n key: \"file\",\n writable: true,\n\n get: (secretId) =>\n Effect.sync(() => {\n const data = readScopeSecrets(filePath, scopeId);\n return data[secretId] ?? null;\n }),\n\n set: (secretId, value) =>\n Effect.sync(() => {\n const data = readScopeSecrets(filePath, scopeId);\n data[secretId] = value;\n writeScopeSecrets(filePath, scopeId, data);\n }),\n\n delete: (secretId) =>\n Effect.sync(() => {\n const data = readScopeSecrets(filePath, scopeId);\n const had = secretId in data;\n delete data[secretId];\n if (had) writeScopeSecrets(filePath, scopeId, data);\n return had;\n }),\n\n list: () =>\n Effect.sync(() => {\n const data = readScopeSecrets(filePath, scopeId);\n return Object.keys(data).map((k) => ({ id: k, name: k }));\n }),\n});\n\n// ---------------------------------------------------------------------------\n// Plugin definition\n// ---------------------------------------------------------------------------\n\nconst PLUGIN_KEY = \"fileSecrets\";\n\nexport const fileSecretsPlugin = (\n config?: FileSecretsPluginConfig,\n): ExecutorPlugin<typeof PLUGIN_KEY, FileSecretsExtension> =>\n definePlugin({\n key: PLUGIN_KEY,\n init: (ctx) =>\n Effect.gen(function* () {\n const filePath = authFilePath(config?.directory);\n\n yield* ctx.secrets.addProvider(\n makeScopedProvider(filePath, ctx.scope.id),\n );\n\n return {\n extension: { filePath },\n };\n }),\n });\n"],"mappings":"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","names":[]}
package/dist/core.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  fileSecretsPlugin
3
- } from "./chunk-GAKDI75V.js";
3
+ } from "./chunk-QCGUSGBY.js";
4
4
  export {
5
5
  fileSecretsPlugin
6
6
  };
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  fileSecretsPlugin
3
- } from "./chunk-GAKDI75V.js";
3
+ } from "./chunk-QCGUSGBY.js";
4
4
 
5
5
  // src/promise.ts
6
6
  var fileSecretsPlugin2 = (config) => fileSecretsPlugin(config);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@executor-js/plugin-file-secrets",
3
3
  "type": "module",
4
- "version": "0.0.1-beta.3",
4
+ "version": "0.0.1-beta.4",
5
5
  "license": "MIT",
6
6
  "repository": {
7
7
  "type": "git",
@@ -33,7 +33,7 @@
33
33
  "test:watch": "vitest"
34
34
  },
35
35
  "dependencies": {
36
- "@executor-js/sdk": "0.0.1-beta.2",
36
+ "@executor-js/sdk": "0.0.1-beta.4",
37
37
  "effect": "^3.21.0"
38
38
  },
39
39
  "devDependencies": {
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["import { Effect, Schema } from \"effect\";\nimport {\n definePlugin,\n type ExecutorPlugin,\n type SecretProvider,\n} from \"@executor-js/sdk/core\";\nimport * as fs from \"node:fs\";\nimport * as path from \"node:path\";\n\n// ---------------------------------------------------------------------------\n// XDG data dir resolution\n// ---------------------------------------------------------------------------\n\nconst APP_NAME = \"executor\";\n\nconst xdgDataHome = (): string =>\n process.env.XDG_DATA_HOME?.trim() ||\n path.join(\n process.env.HOME || process.env.USERPROFILE || \"~\",\n \".local\",\n \"share\",\n );\n\nconst authDir = (overrideDir?: string): string =>\n overrideDir ?? path.join(xdgDataHome(), APP_NAME);\n\nconst authFilePath = (overrideDir?: string): string =>\n path.join(authDir(overrideDir), \"auth.json\");\n\n// ---------------------------------------------------------------------------\n// Schema for the auth file\n//\n// Top-level keys are scope IDs, values are { secretId: secretValue } maps.\n// { \"web-a1b2c3d4\": { \"github-token\": \"ghp_xxx\" } }\n// ---------------------------------------------------------------------------\n\nconst ScopedAuthFile = Schema.Record({\n key: Schema.String,\n value: Schema.Record({ key: Schema.String, value: Schema.String }),\n});\nconst decodeScopedAuthFile = Schema.decodeUnknownSync(ScopedAuthFile);\n\n// ---------------------------------------------------------------------------\n// File I/O with restricted permissions\n// ---------------------------------------------------------------------------\n\nconst readFullFile = (\n filePath: string,\n): Record<string, Record<string, string>> => {\n try {\n if (!fs.existsSync(filePath)) return {};\n const raw = fs.readFileSync(filePath, \"utf-8\");\n return decodeScopedAuthFile(JSON.parse(raw));\n } catch {\n return {};\n }\n};\n\nconst readScopeSecrets = (\n filePath: string,\n scopeId: string,\n): Record<string, string> => readFullFile(filePath)[scopeId] ?? {};\n\nconst writeScopeSecrets = (\n filePath: string,\n scopeId: string,\n secrets: Record<string, string>,\n): void => {\n const dir = path.dirname(filePath);\n if (!fs.existsSync(dir)) {\n fs.mkdirSync(dir, { recursive: true, mode: 0o700 });\n }\n const full = readFullFile(filePath);\n if (Object.keys(secrets).length === 0) {\n delete full[scopeId];\n } else {\n full[scopeId] = secrets;\n }\n const tmp = `${filePath}.tmp`;\n fs.writeFileSync(tmp, JSON.stringify(full, null, 2), { mode: 0o600 });\n fs.renameSync(tmp, filePath);\n};\n\n// ---------------------------------------------------------------------------\n// Plugin config\n// ---------------------------------------------------------------------------\n\nexport interface FileSecretsPluginConfig {\n /** Override the directory for auth.json (default: XDG data dir) */\n readonly directory?: string;\n}\n\n// ---------------------------------------------------------------------------\n// Plugin extension — public API on executor.fileSecrets\n// ---------------------------------------------------------------------------\n\nexport interface FileSecretsExtension {\n /** Path to the auth file */\n readonly filePath: string;\n}\n\n// ---------------------------------------------------------------------------\n// Provider factory (internal)\n// ---------------------------------------------------------------------------\n\nconst makeScopedProvider = (\n filePath: string,\n scopeId: string,\n): SecretProvider => ({\n key: \"file\",\n writable: true,\n\n get: (secretId) =>\n Effect.sync(() => {\n const data = readScopeSecrets(filePath, scopeId);\n return data[secretId] ?? null;\n }),\n\n set: (secretId, value) =>\n Effect.sync(() => {\n const data = readScopeSecrets(filePath, scopeId);\n data[secretId] = value;\n writeScopeSecrets(filePath, scopeId, data);\n }),\n\n delete: (secretId) =>\n Effect.sync(() => {\n const data = readScopeSecrets(filePath, scopeId);\n const had = secretId in data;\n delete data[secretId];\n if (had) writeScopeSecrets(filePath, scopeId, data);\n return had;\n }),\n\n list: () =>\n Effect.sync(() => {\n const data = readScopeSecrets(filePath, scopeId);\n return Object.keys(data).map((k) => ({ id: k, name: k }));\n }),\n});\n\n// ---------------------------------------------------------------------------\n// Plugin definition\n// ---------------------------------------------------------------------------\n\nconst PLUGIN_KEY = \"fileSecrets\";\n\nexport const fileSecretsPlugin = (\n config?: FileSecretsPluginConfig,\n): ExecutorPlugin<typeof PLUGIN_KEY, FileSecretsExtension> =>\n definePlugin({\n key: PLUGIN_KEY,\n init: (ctx) =>\n Effect.gen(function* () {\n const filePath = authFilePath(config?.directory);\n\n yield* ctx.secrets.addProvider(\n makeScopedProvider(filePath, ctx.scope.id),\n );\n\n return {\n extension: { filePath },\n };\n }),\n });\n"],"mappings":"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","names":[]}