Unified · Split
| @@ -13,7 +13,7 @@ · 12 unmodified lines | ||
| 13 | 13 | }, |
| 14 | 14 | "apps/server": { |
| 15 | 15 | "name": "@executor/server", |
| 16 | − "version": "0.0.0", | |
| 16 | + "version": "1.4.0-beta.0", | |
| 17 | 17 | "dependencies": { |
| 18 | 18 | "@effect/platform": "catalog:", |
| 19 | 19 | "@effect/sql": "catalog:", |
| @@ -40,7 +40,7 @@ · 20 unmodified lines | ||
| 40 | 40 | }, |
| 41 | 41 | "apps/web": { |
| 42 | 42 | "name": "@executor/web", |
| 43 | − "version": "0.0.0", | |
| 43 | + "version": "1.4.0-beta.0", | |
| 44 | 44 | "dependencies": { |
| 45 | 45 | "@executor/plugin-google-discovery": "workspace:*", |
| 46 | 46 | "@executor/plugin-graphql": "workspace:*", |
| @@ -72,7 +72,7 @@ · 25 unmodified lines | ||
| 72 | 72 | }, |
| 73 | 73 | "packages/clients/react": { |
| 74 | 74 | "name": "@executor/react", |
| 75 | − "version": "0.0.0", | |
| 75 | + "version": "1.4.0-beta.0", | |
| 76 | 76 | "dependencies": { |
| 77 | 77 | "@effect-atom/atom": "^0.5.3", |
| 78 | 78 | "@effect-atom/atom-react": "^0.5.0", |
| @@ -91,7 +91,7 @@ · 12 unmodified lines | ||
| 91 | 91 | }, |
| 92 | 92 | "packages/core/api": { |
| 93 | 93 | "name": "@executor/api", |
| 94 | − "version": "0.0.0", | |
| 94 | + "version": "1.4.0-beta.0", | |
| 95 | 95 | "dependencies": { |
| 96 | 96 | "@effect/platform": "catalog:", |
| 97 | 97 | "@executor/sdk": "workspace:*", |
| @@ -105,7 +105,7 @@ · 7 unmodified lines | ||
| 105 | 105 | }, |
| 106 | 106 | "packages/core/execution": { |
| 107 | 107 | "name": "@executor/execution", |
| 108 | − "version": "0.0.0", | |
| 108 | + "version": "1.4.0-beta.0", | |
| 109 | 109 | "dependencies": { |
| 110 | 110 | "@executor/codemode-core": "workspace:*", |
| 111 | 111 | "@executor/runtime-quickjs": "workspace:*", |
| @@ -119,7 +119,7 @@ · 7 unmodified lines | ||
| 119 | 119 | }, |
| 120 | 120 | "packages/core/sdk": { |
| 121 | 121 | "name": "@executor/sdk", |
| 122 | − "version": "0.0.1", | |
| 122 | + "version": "1.4.0-beta.0", | |
| 123 | 123 | "dependencies": { |
| 124 | 124 | "effect": "catalog:", |
| 125 | 125 | }, |
| @@ -131,7 +131,7 @@ · 5 unmodified lines | ||
| 131 | 131 | }, |
| 132 | 132 | "packages/core/storage-file": { |
| 133 | 133 | "name": "@executor/storage-file", |
| 134 | − "version": "0.0.0", | |
| 134 | + "version": "1.4.0-beta.0", | |
| 135 | 135 | "dependencies": { |
| 136 | 136 | "@effect/sql": "catalog:", |
| 137 | 137 | "@executor/sdk": "workspace:*", |
| @@ -147,7 +147,7 @@ · 9 unmodified lines | ||
| 147 | 147 | }, |
| 148 | 148 | "packages/hosts/mcp": { |
| 149 | 149 | "name": "@executor/host-mcp", |
| 150 | − "version": "0.0.0", | |
| 150 | + "version": "1.4.0-beta.0", | |
| 151 | 151 | "dependencies": { |
| 152 | 152 | "@executor/execution": "workspace:*", |
| 153 | 153 | "@executor/sdk": "workspace:*", |
| @@ -162,7 +162,7 @@ · 8 unmodified lines | ||
| 162 | 162 | }, |
| 163 | 163 | "packages/kernel/core": { |
| 164 | 164 | "name": "@executor/codemode-core", |
| 165 | − "version": "0.0.0", | |
| 165 | + "version": "1.4.0-beta.0", | |
| 166 | 166 | "dependencies": { |
| 167 | 167 | "@standard-schema/spec": "^1.0.0", |
| 168 | 168 | "ajv": "^8.17.1", |
| @@ -178,7 +178,7 @@ · 9 unmodified lines | ||
| 178 | 178 | }, |
| 179 | 179 | "packages/kernel/ir": { |
| 180 | 180 | "name": "@executor/ir", |
| 181 | − "version": "0.0.0", | |
| 181 | + "version": "1.4.0-beta.0", | |
| 182 | 182 | "dependencies": { |
| 183 | 183 | "effect": "catalog:", |
| 184 | 184 | }, |
| @@ -191,7 +191,7 @@ · 6 unmodified lines | ||
| 191 | 191 | }, |
| 192 | 192 | "packages/kernel/runtime-quickjs": { |
| 193 | 193 | "name": "@executor/runtime-quickjs", |
| 194 | − "version": "0.0.0", | |
| 194 | + "version": "1.4.0-beta.0", | |
| 195 | 195 | "dependencies": { |
| 196 | 196 | "@executor/codemode-core": "workspace:*", |
| 197 | 197 | "effect": "catalog:", |
| @@ -206,7 +206,7 @@ · 8 unmodified lines | ||
| 206 | 206 | }, |
| 207 | 207 | "packages/plugins/file-secrets": { |
| 208 | 208 | "name": "@executor/plugin-file-secrets", |
| 209 | − "version": "0.0.0", | |
| 209 | + "version": "1.4.0-beta.0", | |
| 210 | 210 | "dependencies": { |
| 211 | 211 | "@executor/sdk": "workspace:*", |
| 212 | 212 | "effect": "catalog:", |
| @@ -220,7 +220,7 @@ · 7 unmodified lines | ||
| 220 | 220 | }, |
| 221 | 221 | "packages/plugins/google-discovery": { |
| 222 | 222 | "name": "@executor/plugin-google-discovery", |
| 223 | − "version": "0.0.0", | |
| 223 | + "version": "1.4.0-beta.0", | |
| 224 | 224 | "dependencies": { |
| 225 | 225 | "@effect/platform": "catalog:", |
| 226 | 226 | "@executor/api": "workspace:*", |
| @@ -255,7 +255,7 @@ · 28 unmodified lines | ||
| 255 | 255 | }, |
| 256 | 256 | "packages/plugins/graphql": { |
| 257 | 257 | "name": "@executor/plugin-graphql", |
| 258 | − "version": "0.0.0", | |
| 258 | + "version": "1.4.0-beta.0", | |
| 259 | 259 | "dependencies": { |
| 260 | 260 | "@effect/platform": "catalog:", |
| 261 | 261 | "@effect/platform-node": "catalog:", |
| @@ -293,7 +293,7 @@ · 31 unmodified lines | ||
| 293 | 293 | }, |
| 294 | 294 | "packages/plugins/keychain": { |
| 295 | 295 | "name": "@executor/plugin-keychain", |
| 296 | − "version": "0.0.0", | |
| 296 | + "version": "1.4.0-beta.0", | |
| 297 | 297 | "dependencies": { |
| 298 | 298 | "@executor/sdk": "workspace:*", |
| 299 | 299 | "@napi-rs/keyring": "^1.2.0", |
| @@ -308,7 +308,7 @@ · 8 unmodified lines | ||
| 308 | 308 | }, |
| 309 | 309 | "packages/plugins/mcp": { |
| 310 | 310 | "name": "@executor/plugin-mcp", |
| 311 | − "version": "0.0.0", | |
| 311 | + "version": "1.4.0-beta.0", | |
| 312 | 312 | "dependencies": { |
| 313 | 313 | "@effect/platform": "catalog:", |
| 314 | 314 | "@effect/platform-node": "catalog:", |
| @@ -347,8 +347,9 @@ · 32 unmodified lines | ||
| 347 | 347 | }, |
| 348 | 348 | "packages/plugins/onepassword": { |
| 349 | 349 | "name": "@executor/plugin-onepassword", |
| 350 | − "version": "0.0.0", | |
| 350 | + "version": "1.4.0-beta.0", | |
| 351 | 351 | "dependencies": { |
| 352 | + "@1password/op-js": "^0.1.13", | |
| 352 | 353 | "@1password/sdk": "^0.4.1-beta.1", |
| 353 | 354 | "@effect-atom/atom-react": "^0.5.0", |
| 354 | 355 | "@effect/platform": "catalog:", |
| @@ -377,7 +378,7 @@ · 22 unmodified lines | ||
| 377 | 378 | }, |
| 378 | 379 | "packages/plugins/openapi": { |
| 379 | 380 | "name": "@executor/plugin-openapi", |
| 380 | − "version": "0.0.0", | |
| 381 | + "version": "1.4.0-beta.0", | |
| 381 | 382 | "dependencies": { |
| 382 | 383 | "@apidevtools/swagger-parser": "^12.1.0", |
| 383 | 384 | "@effect/platform": "catalog:", |
| @@ -418,7 +419,7 @@ · 34 unmodified lines | ||
| 418 | 419 | }, |
| 419 | 420 | "packages/ui": { |
| 420 | 421 | "name": "@executor/ui", |
| 421 | − "version": "0.0.0", | |
| 422 | + "version": "1.4.0-beta.0", | |
| 422 | 423 | "dependencies": { |
| 423 | 424 | "@base-ui/react": "^1.3.0", |
| 424 | 425 | "@hookform/resolvers": "^5.2.2", |
| @@ -469,6 +470,8 @@ · 44 unmodified lines | ||
| 469 | 470 | "vitest": "^3.2.4", |
| 470 | 471 | }, |
| 471 | 472 | "packages": { |
| 473 | + "@1password/op-js": ["@1password/op-js@0.1.13", "", { "dependencies": { "lookpath": "^1.2.2", "semver": "^7.6.2" } }, "sha512-ZZBLxVqywFdvIbLv2xWw2N1ImSi183rRKf90vV19KRMReNyLwuD0dv6IrKrIdrJU33IuV3Gz85Z4K2a1PJTBDg=="], | |
| 474 | + | |
| 472 | 475 | "@1password/sdk": ["@1password/sdk@0.4.1-beta.1", "", { "dependencies": { "@1password/sdk-core": "0.4.1-beta.1" } }, "sha512-QWY6eIIEs9at6kAFbgjZ1vVxg7ygp/MwXJ6/BoBdPkqIk8vfulXu4pjDsVQ87HhddJAD5LVGBXSbQIa+svI3bA=="], |
| 473 | 476 | |
| 474 | 477 | "@1password/sdk-core": ["@1password/sdk-core@0.4.1-beta.1", "", {}, "sha512-/otbg1JVhsEn6oUIeReoT9TmFr8J7KBwr9UuRVfJFwwGG3bHPF8ewT+LhRimQeJtypqQ69ZVuOYkxknD4iQHxw=="], |
| @@ -1603,6 +1606,8 @@ · 1128 unmodified lines | ||
| 1603 | 1606 | |
| 1604 | 1607 | "longest-streak": ["longest-streak@3.1.0", "", {}, "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g=="], |
| 1605 | 1608 | |
| 1609 | + "lookpath": ["lookpath@1.2.3", "", { "bin": { "lookpath": "bin/lookpath.js" } }, "sha512-kthRVhf4kH4+HW3anM4UBHxsw/XFESf13euCEldhXr6GpBdmBoa7rDd7WO5G0Mhd4G5XtKTcEy8OR0iRZXpS3Q=="], | |
| 1610 | + | |
| 1606 | 1611 | "loupe": ["loupe@3.2.1", "", {}, "sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ=="], |
| 1607 | 1612 | |
| 1608 | 1613 | "lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="], |
| @@ -1891,7 +1896,7 @@ · 282 unmodified lines | ||
| 1891 | 1896 | |
| 1892 | 1897 | "scheduler": ["scheduler@0.27.0", "", {}, "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q=="], |
| 1893 | 1898 | |
| 1894 | − "semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], | |
| 1899 | + "semver": ["semver@7.7.4", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA=="], | |
| 1895 | 1900 | |
| 1896 | 1901 | "send": ["send@1.2.1", "", { "dependencies": { "debug": "^4.4.3", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "fresh": "^2.0.0", "http-errors": "^2.0.1", "mime-types": "^3.0.2", "ms": "^2.1.3", "on-finished": "^2.4.1", "range-parser": "^1.2.1", "statuses": "^2.0.2" } }, "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ=="], |
| 1897 | 1902 | |
| @@ -2081,6 +2086,10 @@ · 183 unmodified lines | ||
| 2081 | 2086 | |
| 2082 | 2087 | "@babel/code-frame/js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="], |
| 2083 | 2088 | |
| 2089 | + "@babel/core/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], | |
| 2090 | + | |
| 2091 | + "@babel/helper-compilation-targets/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], | |
| 2092 | + | |
| 2084 | 2093 | "@executor/sdk/typescript": ["typescript@6.0.2", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-bGdAIrZ0wiGDo5l8c++HWtbaNCWTS4UTv7RaTH/ThVIgjkveJt83m74bBHMJkuCbslY8ixgLBVZJIOiQlQTjfQ=="], |
| 2085 | 2094 | |
| 2086 | 2095 | "@reduxjs/toolkit/immer": ["immer@11.1.4", "", {}, "sha512-XREFCPo6ksxVzP4E0ekD5aMdf8WMwmdNaz6vuvxgI40UaEiu6q3p8X52aU6GdyvLY3XXX/8R7JOTXStz/nBbRw=="], |
| @@ -2111,8 +2120,6 @@ · 24 unmodified lines | ||
| 2111 | 2120 | |
| 2112 | 2121 | "mermaid/marked": ["marked@16.4.2", "", { "bin": { "marked": "bin/marked.js" } }, "sha512-TI3V8YYWvkVf3KJe1dRkpnjs68JUPyEa5vjKrp1XEEJUAOaQc+Qj+L1qWbPd0SJuAdQkFU0h73sXXqwDYxsiDA=="], |
| 2113 | 2122 | |
| 2114 | − "node-abi/semver": ["semver@7.7.4", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA=="], | |
| 2115 | − | |
| 2116 | 2123 | "parse-entities/@types/unist": ["@types/unist@2.0.11", "", {}, "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA=="], |
| 2117 | 2124 | |
| 2118 | 2125 | "vite-node/vite": ["vite@7.3.1", "", { "dependencies": { "esbuild": "^0.27.0", "fdir": "^6.5.0", "picomatch": "^4.0.3", "postcss": "^8.5.6", "rollup": "^4.43.0", "tinyglobby": "^0.2.15" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "jiti": ">=1.21.0", "less": "^4.0.0", "lightningcss": "^1.21.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA=="], |
| @@ -14,12 +14,13 @@ · 13 unmodified lines | ||
| 14 | 14 | "test:watch": "vitest" |
| 15 | 15 | }, |
| 16 | 16 | "dependencies": { |
| 17 | + "@1password/op-js": "^0.1.13", | |
| 17 | 18 | "@1password/sdk": "^0.4.1-beta.1", |
| 19 | + "@effect-atom/atom-react": "^0.5.0", | |
| 20 | + "@effect/platform": "catalog:", | |
| 18 | 21 | "@executor/api": "workspace:*", |
| 19 | 22 | "@executor/sdk": "workspace:*", |
| 20 | − "effect": "catalog:", | |
| 21 | − "@effect/platform": "catalog:", | |
| 22 | − "@effect-atom/atom-react": "^0.5.0" | |
| 23 | + "effect": "catalog:" | |
| 23 | 24 | }, |
| 24 | 25 | "devDependencies": { |
| 25 | 26 | "@effect/vitest": "catalog:", |
| @@ -34,9 +35,17 @@ · 8 unmodified lines | ||
| 34 | 35 | "@executor/ui": "workspace:*" |
| 35 | 36 | }, |
| 36 | 37 | "peerDependenciesMeta": { |
| 37 | − "react": { "optional": true }, | |
| 38 | − "@effect-atom/atom-react": { "optional": true }, | |
| 39 | − "@executor/react": { "optional": true }, | |
| 40 | − "@executor/ui": { "optional": true } | |
| 38 | + "react": { | |
| 39 | + "optional": true | |
| 40 | + }, | |
| 41 | + "@effect-atom/atom-react": { | |
| 42 | + "optional": true | |
| 43 | + }, | |
| 44 | + "@executor/react": { | |
| 45 | + "optional": true | |
| 46 | + }, | |
| 47 | + "@executor/ui": { | |
| 48 | + "optional": true | |
| 49 | + } | |
| 41 | 50 | } |
| 42 | 51 | } |
| @@ -1,115 +0,0 @@ | ||
| 1 | −import { Duration, Effect } from "effect"; | |
| 2 | −import { | |
| 3 | − createClient, | |
| 4 | − DesktopAuth, | |
| 5 | − type Client, | |
| 6 | −} from "@1password/sdk"; | |
| 7 | − | |
| 8 | −import { OnePasswordError } from "./errors"; | |
| 9 | − | |
| 10 | −// --------------------------------------------------------------------------- | |
| 11 | −// Resolved auth — raw credentials ready for the SDK | |
| 12 | −// --------------------------------------------------------------------------- | |
| 13 | − | |
| 14 | −export type ResolvedAuth = | |
| 15 | − | { readonly kind: "desktop-app"; readonly accountName: string } | |
| 16 | − | { readonly kind: "service-account"; readonly token: string }; | |
| 17 | − | |
| 18 | −// --------------------------------------------------------------------------- | |
| 19 | −// 1Password client wrapper using the Effect "use" pattern | |
| 20 | −// --------------------------------------------------------------------------- | |
| 21 | − | |
| 22 | −export interface OnePasswordClient { | |
| 23 | − /** The raw 1Password SDK client (escape hatch) */ | |
| 24 | − readonly client: Client; | |
| 25 | − | |
| 26 | − /** | |
| 27 | − * Execute a function against the 1Password client with automatic | |
| 28 | − * error handling, timeout, and tracing. | |
| 29 | − */ | |
| 30 | − readonly use: <A>( | |
| 31 | − fn: (client: Client) => Promise<A>, | |
| 32 | − operation?: string, | |
| 33 | − ) => Effect.Effect<A, OnePasswordError>; | |
| 34 | −} | |
| 35 | − | |
| 36 | −// --------------------------------------------------------------------------- | |
| 37 | −// Factory | |
| 38 | −// --------------------------------------------------------------------------- | |
| 39 | − | |
| 40 | −const DEFAULT_TIMEOUT_MS = 15_000; | |
| 41 | − | |
| 42 | −export const makeOnePasswordClient = ( | |
| 43 | − auth: ResolvedAuth, | |
| 44 | − timeoutMs: number = DEFAULT_TIMEOUT_MS, | |
| 45 | −): Effect.Effect<OnePasswordClient, OnePasswordError> => | |
| 46 | − Effect.gen(function* () { | |
| 47 | − const timeout = Duration.millis(timeoutMs); | |
| 48 | − | |
| 49 | − const client = yield* Effect.tryPromise({ | |
| 50 | − try: () => | |
| 51 | − createClient({ | |
| 52 | − auth: | |
| 53 | − auth.kind === "desktop-app" | |
| 54 | − ? new DesktopAuth(auth.accountName) | |
| 55 | − : auth.token, | |
| 56 | − integrationName: "Executor", | |
| 57 | − integrationVersion: "0.0.0", | |
| 58 | − }), | |
| 59 | − catch: (cause) => | |
| 60 | − new OnePasswordError({ | |
| 61 | − operation: "client setup", | |
| 62 | − message: cause instanceof Error ? cause.message : String(cause), | |
| 63 | − }), | |
| 64 | − }).pipe( | |
| 65 | − Effect.timeoutFail({ | |
| 66 | − duration: timeout, | |
| 67 | − onTimeout: () => | |
| 68 | − new OnePasswordError({ | |
| 69 | − operation: "client setup", | |
| 70 | − message: [ | |
| 71 | − `timed out after ${Math.floor(timeoutMs / 1000)}s.`, | |
| 72 | − "Troubleshooting:", | |
| 73 | − "1. Make sure the 1Password desktop app is open and unlocked", | |
| 74 | − "2. Check for an approval prompt in the 1Password app — it may be behind other windows", | |
| 75 | − "3. Ensure 'Developer > Connect with 1Password CLI' is enabled in 1Password Settings", | |
| 76 | − "4. Make sure no other app or terminal is waiting for 1Password approval (only one prompt at a time)", | |
| 77 | − "5. Try quitting 1Password completely and reopening it, then retry", | |
| 78 | − ].join("\n"), | |
| 79 | − }), | |
| 80 | − }), | |
| 81 | − ); | |
| 82 | − | |
| 83 | − const use = <A>( | |
| 84 | − fn: (client: Client) => Promise<A>, | |
| 85 | − operation = "use", | |
| 86 | − ): Effect.Effect<A, OnePasswordError> => | |
| 87 | − Effect.tryPromise({ | |
| 88 | − try: () => fn(client), | |
| 89 | − catch: (cause) => | |
| 90 | − new OnePasswordError({ | |
| 91 | − operation, | |
| 92 | − message: cause instanceof Error ? cause.message : String(cause), | |
| 93 | − }), | |
| 94 | − }).pipe( | |
| 95 | − Effect.timeoutFail({ | |
| 96 | − duration: timeout, | |
| 97 | − onTimeout: () => | |
| 98 | − new OnePasswordError({ | |
| 99 | − operation, | |
| 100 | − message: [ | |
| 101 | − `timed out after ${Math.floor(timeoutMs / 1000)}s.`, | |
| 102 | − "Troubleshooting:", | |
| 103 | − "1. Make sure the 1Password desktop app is open and unlocked", | |
| 104 | − "2. Check for an approval prompt in the 1Password app — it may be behind other windows", | |
| 105 | − "3. Ensure 'Developer > Connect with 1Password CLI' is enabled in 1Password Settings", | |
| 106 | − "4. Make sure no other app or terminal is waiting for 1Password approval (only one prompt at a time)", | |
| 107 | − "5. Try quitting 1Password completely and reopening it, then retry", | |
| 108 | − ].join("\n"), | |
| 109 | − }), | |
| 110 | − }), | |
| 111 | − Effect.withSpan(`onepassword.${operation}`), | |
| 112 | − ); | |
| 113 | − | |
| 114 | − return { client, use } satisfies OnePasswordClient; | |
| 115 | − }).pipe(Effect.withSpan("onepassword.make_client")); | |
| @@ -1,4 +1,11 @@ | ||
| 1 | 1 | export { onepasswordPlugin, type OnePasswordExtension, type OnePasswordPluginOptions } from "./plugin"; |
| 2 | 2 | export { OnePasswordConfig, Vault, ConnectionStatus, OnePasswordAuth, DesktopAppAuth, ServiceAccountAuth } from "./types"; |
| 3 | 3 | export { OnePasswordError } from "./errors"; |
| 4 | −export { makeOnePasswordClient, type OnePasswordClient, type ResolvedAuth } from "./client"; | |
| 4 | +export { | |
| 5 | + makeOnePasswordService, | |
| 6 | + makeNativeSdkService, | |
| 7 | + makeCliService, | |
| 8 | + OnePasswordServiceTag, | |
| 9 | + type OnePasswordService, | |
| 10 | + type ResolvedAuth, | |
| 11 | +} from "./service"; | |
| @@ -12,7 +12,11 @@ import { · 11 unmodified lines | ||
| 12 | 12 | import { OnePasswordConfig, Vault, ConnectionStatus } from "./types"; |
| 13 | 13 | import type { OnePasswordAuth } from "./types"; |
| 14 | 14 | import { OnePasswordError } from "./errors"; |
| 15 | −import { makeOnePasswordClient, type ResolvedAuth, type OnePasswordClient } from "./client"; | |
| 15 | +import { | |
| 16 | + makeOnePasswordService, | |
| 17 | + type ResolvedAuth, | |
| 18 | + type OnePasswordService, | |
| 19 | +} from "./service"; | |
| 16 | 20 | |
| 17 | 21 | // --------------------------------------------------------------------------- |
| 18 | 22 | // Constants |
| @@ -79,13 +83,13 @@ const resolveAuth = ( · 60 unmodified lines | ||
| 79 | 83 | ); |
| 80 | 84 | }; |
| 81 | 85 | |
| 82 | −const getClientFromConfig = ( | |
| 86 | +const getServiceFromConfig = ( | |
| 83 | 87 | config: OnePasswordConfig, |
| 84 | 88 | ctx: PluginContext, |
| 85 | 89 | timeoutMs: number, |
| 86 | −): Effect.Effect<OnePasswordClient, OnePasswordError> => | |
| 90 | +): Effect.Effect<OnePasswordService, OnePasswordError> => | |
| 87 | 91 | resolveAuth(config.auth, ctx).pipe( |
| 88 | − Effect.flatMap((resolved) => makeOnePasswordClient(resolved, timeoutMs)), | |
| 92 | + Effect.flatMap((resolved) => makeOnePasswordService(resolved, { timeoutMs })), | |
| 89 | 93 | ); |
| 90 | 94 | |
| 91 | 95 | // --------------------------------------------------------------------------- |
| @@ -109,13 +113,8 @@ const makeProvider = ( · 17 unmodified lines | ||
| 109 | 113 | ? secretId |
| 110 | 114 | : `op://${config.vaultId}/${secretId}/${CREDENTIAL_FIELD}`; |
| 111 | 115 | |
| 112 | − return getClientFromConfig(config, ctx, timeoutMs).pipe( | |
| 113 | − Effect.flatMap((op) => | |
| 114 | − op.use( | |
| 115 | − (client) => client.secrets.resolve(uri), | |
| 116 | − "secret resolution", | |
| 117 | − ), | |
| 118 | − ), | |
| 116 | + return getServiceFromConfig(config, ctx, timeoutMs).pipe( | |
| 117 | + Effect.flatMap((svc) => svc.resolveSecret(uri)), | |
| 119 | 118 | Effect.map((v): string | null => v), |
| 120 | 119 | Effect.orElseSucceed(() => null), |
| 121 | 120 | ); |
| @@ -127,13 +126,8 @@ const makeProvider = ( · 5 unmodified lines | ||
| 127 | 126 | getConfig().pipe( |
| 128 | 127 | Effect.flatMap((config) => { |
| 129 | 128 | if (!config) return Effect.succeed([] as { id: string; name: string }[]); |
| 130 | − return getClientFromConfig(config, ctx, timeoutMs).pipe( | |
| 131 | − Effect.flatMap((op) => | |
| 132 | − op.use( | |
| 133 | − (client) => client.items.list(config.vaultId), | |
| 134 | − "item listing", | |
| 135 | − ), | |
| 136 | − ), | |
| 129 | + return getServiceFromConfig(config, ctx, timeoutMs).pipe( | |
| 130 | + Effect.flatMap((svc) => svc.listItems(config.vaultId)), | |
| 137 | 131 | Effect.map((items) => |
| 138 | 132 | items.map((item) => ({ id: item.id, name: item.title })), |
| 139 | 133 | ), |
| @@ -187,6 +181,8 @@ export interface OnePasswordPluginOptions { · 47 unmodified lines | ||
| 187 | 181 | readonly kv: ScopedKv; |
| 188 | 182 | /** Request timeout in ms (default: 15000) */ |
| 189 | 183 | readonly timeoutMs?: number; |
| 184 | + /** Force use of the native SDK instead of the CLI (default: false) */ | |
| 185 | + readonly preferSdk?: boolean; | |
| 190 | 186 | } |
| 191 | 187 | |
| 192 | 188 | export const onepasswordPlugin = ( |
| @@ -222,11 +218,8 @@ export const onepasswordPlugin = ( · 29 unmodified lines | ||
| 222 | 218 | error: "Not configured", |
| 223 | 219 | }); |
| 224 | 220 | } |
| 225 | − const op = yield* getClientFromConfig(config, ctx, timeoutMs); | |
| 226 | − const vaults = yield* op.use( | |
| 227 | − (client) => client.vaults.list({ decryptDetails: true }), | |
| 228 | − "connection check", | |
| 229 | − ); | |
| 221 | + const svc = yield* getServiceFromConfig(config, ctx, timeoutMs); | |
| 222 | + const vaults = yield* svc.listVaults(); | |
| 230 | 223 | const vault = vaults.find((v) => v.id === config.vaultId); |
| 231 | 224 | return new ConnectionStatus({ |
| 232 | 225 | connected: true, |
| @@ -237,11 +230,11 @@ export const onepasswordPlugin = ( · 4 unmodified lines | ||
| 237 | 230 | listVaults: (auth) => |
| 238 | 231 | Effect.gen(function* () { |
| 239 | 232 | const resolved = yield* resolveAuth(auth, ctx); |
| 240 | − const op = yield* makeOnePasswordClient(resolved, timeoutMs); | |
| 241 | − const vaults = yield* op.use( | |
| 242 | − (client) => client.vaults.list({ decryptDetails: true }), | |
| 243 | − "vault listing", | |
| 244 | − ); | |
| 233 | + const svc = yield* makeOnePasswordService(resolved, { | |
| 234 | + timeoutMs, | |
| 235 | + preferSdk: options.preferSdk, | |
| 236 | + }); | |
| 237 | + const vaults = yield* svc.listVaults(); | |
| 245 | 238 | return vaults |
| 246 | 239 | .map((v) => new Vault({ id: v.id, name: v.title })) |
| 247 | 240 | .sort((a, b) => a.name.localeCompare(b.name)); |
| @@ -256,11 +249,8 @@ export const onepasswordPlugin = ( · 8 unmodified lines | ||
| 256 | 249 | message: "1Password is not configured", |
| 257 | 250 | }); |
| 258 | 251 | } |
| 259 | − const op = yield* getClientFromConfig(config, ctx, timeoutMs); | |
| 260 | − return yield* op.use( | |
| 261 | − (client) => client.secrets.resolve(uri), | |
| 262 | − "secret resolution", | |
| 263 | − ); | |
| 252 | + const svc = yield* getServiceFromConfig(config, ctx, timeoutMs); | |
| 253 | + return yield* svc.resolveSecret(uri); | |
| 264 | 254 | }), |
| 265 | 255 | }; |
| 266 | 256 | |
| @@ -0,0 +1,221 @@ | ||
| 1 | +import { Context, Duration, Effect } from "effect"; | |
| 2 | +import { createClient, DesktopAuth } from "@1password/sdk"; | |
| 3 | +import * as op from "@1password/op-js"; | |
| 4 | + | |
| 5 | +import { OnePasswordError } from "./errors"; | |
| 6 | + | |
| 7 | +// --------------------------------------------------------------------------- | |
| 8 | +// Canonical service interface — all backends (SDK, CLI) implement this | |
| 9 | +// --------------------------------------------------------------------------- | |
| 10 | + | |
| 11 | +export interface OnePasswordVault { | |
| 12 | + readonly id: string; | |
| 13 | + readonly title: string; | |
| 14 | +} | |
| 15 | + | |
| 16 | +export interface OnePasswordItem { | |
| 17 | + readonly id: string; | |
| 18 | + readonly title: string; | |
| 19 | +} | |
| 20 | + | |
| 21 | +export interface OnePasswordService { | |
| 22 | + /** Resolve a secret by op:// URI */ | |
| 23 | + readonly resolveSecret: ( | |
| 24 | + uri: string, | |
| 25 | + ) => Effect.Effect<string, OnePasswordError>; | |
| 26 | + | |
| 27 | + /** List accessible vaults */ | |
| 28 | + readonly listVaults: () => Effect.Effect< | |
| 29 | + ReadonlyArray<OnePasswordVault>, | |
| 30 | + OnePasswordError | |
| 31 | + >; | |
| 32 | + | |
| 33 | + /** List items in a vault */ | |
| 34 | + readonly listItems: ( | |
| 35 | + vaultId: string, | |
| 36 | + ) => Effect.Effect<ReadonlyArray<OnePasswordItem>, OnePasswordError>; | |
| 37 | +} | |
| 38 | + | |
| 39 | +export class OnePasswordServiceTag extends Context.Tag( | |
| 40 | + "@executor/plugin-onepassword/OnePasswordService", | |
| 41 | +)<OnePasswordServiceTag, OnePasswordService>() {} | |
| 42 | + | |
| 43 | +// --------------------------------------------------------------------------- | |
| 44 | +// Resolved auth — raw credentials ready for any backend | |
| 45 | +// --------------------------------------------------------------------------- | |
| 46 | + | |
| 47 | +export type ResolvedAuth = | |
| 48 | + | { readonly kind: "desktop-app"; readonly accountName: string } | |
| 49 | + | { readonly kind: "service-account"; readonly token: string }; | |
| 50 | + | |
| 51 | +// --------------------------------------------------------------------------- | |
| 52 | +// SDK backend — uses @1password/sdk native IPC | |
| 53 | +// --------------------------------------------------------------------------- | |
| 54 | + | |
| 55 | +const DEFAULT_TIMEOUT_MS = 15_000; | |
| 56 | + | |
| 57 | +const makeTimeoutMessage = (operation: string, timeoutMs: number): string => | |
| 58 | + [ | |
| 59 | + `${operation}: timed out after ${Math.floor(timeoutMs / 1000)}s.`, | |
| 60 | + "Troubleshooting:", | |
| 61 | + "1. Make sure the 1Password desktop app is open and unlocked", | |
| 62 | + "2. Check for an approval prompt in the 1Password app — it may be behind other windows", | |
| 63 | + "3. Ensure 'Developer > Connect with 1Password CLI' is enabled in 1Password Settings", | |
| 64 | + "4. Make sure no other app or terminal is waiting for 1Password approval (only one prompt at a time)", | |
| 65 | + "5. Try quitting 1Password completely and reopening it, then retry", | |
| 66 | + ].join("\n"); | |
| 67 | + | |
| 68 | +export const makeNativeSdkService = ( | |
| 69 | + auth: ResolvedAuth, | |
| 70 | + timeoutMs: number = DEFAULT_TIMEOUT_MS, | |
| 71 | +): Effect.Effect<OnePasswordService, OnePasswordError> => | |
| 72 | + Effect.gen(function* () { | |
| 73 | + const timeout = Duration.millis(timeoutMs); | |
| 74 | + | |
| 75 | + const client = yield* Effect.tryPromise({ | |
| 76 | + try: () => | |
| 77 | + createClient({ | |
| 78 | + auth: | |
| 79 | + auth.kind === "desktop-app" | |
| 80 | + ? new DesktopAuth(auth.accountName) | |
| 81 | + : auth.token, | |
| 82 | + integrationName: "Executor", | |
| 83 | + integrationVersion: "0.0.0", | |
| 84 | + }), | |
| 85 | + catch: (cause) => | |
| 86 | + new OnePasswordError({ | |
| 87 | + operation: "client setup", | |
| 88 | + message: cause instanceof Error ? cause.message : String(cause), | |
| 89 | + }), | |
| 90 | + }).pipe( | |
| 91 | + Effect.timeoutFail({ | |
| 92 | + duration: timeout, | |
| 93 | + onTimeout: () => | |
| 94 | + new OnePasswordError({ | |
| 95 | + operation: "client setup", | |
| 96 | + message: makeTimeoutMessage("client setup", timeoutMs), | |
| 97 | + }), | |
| 98 | + }), | |
| 99 | + ); | |
| 100 | + | |
| 101 | + const wrap = <A>( | |
| 102 | + fn: () => Promise<A>, | |
| 103 | + operation: string, | |
| 104 | + ): Effect.Effect<A, OnePasswordError> => | |
| 105 | + Effect.tryPromise({ | |
| 106 | + try: fn, | |
| 107 | + catch: (cause) => | |
| 108 | + new OnePasswordError({ | |
| 109 | + operation, | |
| 110 | + message: cause instanceof Error ? cause.message : String(cause), | |
| 111 | + }), | |
| 112 | + }).pipe( | |
| 113 | + Effect.timeoutFail({ | |
| 114 | + duration: timeout, | |
| 115 | + onTimeout: () => | |
| 116 | + new OnePasswordError({ | |
| 117 | + operation, | |
| 118 | + message: makeTimeoutMessage(operation, timeoutMs), | |
| 119 | + }), | |
| 120 | + }), | |
| 121 | + Effect.withSpan(`onepassword.sdk.${operation}`), | |
| 122 | + ); | |
| 123 | + | |
| 124 | + return OnePasswordServiceTag.of({ | |
| 125 | + resolveSecret: (uri) => | |
| 126 | + wrap(() => client.secrets.resolve(uri), "secret resolution"), | |
| 127 | + | |
| 128 | + listVaults: () => | |
| 129 | + wrap( | |
| 130 | + () => client.vaults.list({ decryptDetails: true }), | |
| 131 | + "vault listing", | |
| 132 | + ).pipe( | |
| 133 | + Effect.map((vaults) => | |
| 134 | + vaults.map((v) => ({ id: v.id, title: v.title })), | |
| 135 | + ), | |
| 136 | + ), | |
| 137 | + | |
| 138 | + listItems: (vaultId) => | |
| 139 | + wrap(() => client.items.list(vaultId), "item listing").pipe( | |
| 140 | + Effect.map((items) => | |
| 141 | + items.map((i) => ({ id: i.id, title: i.title })), | |
| 142 | + ), | |
| 143 | + ), | |
| 144 | + }); | |
| 145 | + }).pipe(Effect.withSpan("onepassword.sdk.make_service")); | |
| 146 | + | |
| 147 | +// --------------------------------------------------------------------------- | |
| 148 | +// CLI backend — uses @1password/op-js (shells out to `op` CLI) | |
| 149 | +// --------------------------------------------------------------------------- | |
| 150 | + | |
| 151 | +export const makeCliService = ( | |
| 152 | + auth: ResolvedAuth, | |
| 153 | +): Effect.Effect<OnePasswordService, OnePasswordError> => | |
| 154 | + Effect.gen(function* () { | |
| 155 | + // Configure auth | |
| 156 | + if (auth.kind === "service-account") { | |
| 157 | + op.setServiceAccount(auth.token); | |
| 158 | + } else { | |
| 159 | + op.setGlobalFlags({ account: auth.accountName }); | |
| 160 | + } | |
| 161 | + | |
| 162 | + const wrapSync = <A>( | |
| 163 | + fn: () => A, | |
| 164 | + operation: string, | |
| 165 | + ): Effect.Effect<A, OnePasswordError> => | |
| 166 | + Effect.try({ | |
| 167 | + try: fn, | |
| 168 | + catch: (cause) => | |
| 169 | + new OnePasswordError({ | |
| 170 | + operation, | |
| 171 | + message: cause instanceof Error ? cause.message : String(cause), | |
| 172 | + }), | |
| 173 | + }).pipe(Effect.withSpan(`onepassword.cli.${operation}`)); | |
| 174 | + | |
| 175 | + return OnePasswordServiceTag.of({ | |
| 176 | + resolveSecret: (uri) => | |
| 177 | + wrapSync(() => op.read.parse(uri), "secret resolution"), | |
| 178 | + | |
| 179 | + listVaults: () => | |
| 180 | + wrapSync(() => op.vault.list(), "vault listing").pipe( | |
| 181 | + Effect.map((vaults) => | |
| 182 | + vaults.map((v) => ({ id: v.id, title: v.name })), | |
| 183 | + ), | |
| 184 | + ), | |
| 185 | + | |
| 186 | + listItems: (vaultId) => | |
| 187 | + wrapSync( | |
| 188 | + () => op.item.list({ vault: vaultId }), | |
| 189 | + "item listing", | |
| 190 | + ).pipe( | |
| 191 | + Effect.map((items) => | |
| 192 | + items.map((i) => ({ id: i.id, title: i.title })), | |
| 193 | + ), | |
| 194 | + ), | |
| 195 | + }); | |
| 196 | + }).pipe(Effect.withSpan("onepassword.cli.make_service")); | |
| 197 | + | |
| 198 | +// --------------------------------------------------------------------------- | |
| 199 | +// Smart factory — tries CLI first (avoids IPC hang), falls back to SDK | |
| 200 | +// --------------------------------------------------------------------------- | |
| 201 | + | |
| 202 | +export const makeOnePasswordService = ( | |
| 203 | + auth: ResolvedAuth, | |
| 204 | + options?: { readonly preferSdk?: boolean; readonly timeoutMs?: number }, | |
| 205 | +): Effect.Effect<OnePasswordService, OnePasswordError> => { | |
| 206 | + const timeoutMs = options?.timeoutMs ?? DEFAULT_TIMEOUT_MS; | |
| 207 | + | |
| 208 | + if (options?.preferSdk) { | |
| 209 | + return makeNativeSdkService(auth, timeoutMs); | |
| 210 | + } | |
| 211 | + | |
| 212 | + // Default: prefer CLI to avoid the IPC hang bug | |
| 213 | + return makeCliService(auth).pipe( | |
| 214 | + Effect.catchAll((cliError) => | |
| 215 | + // CLI unavailable (e.g. `op` not installed) — fall back to SDK | |
| 216 | + makeNativeSdkService(auth, timeoutMs).pipe( | |
| 217 | + Effect.mapError(() => cliError), | |
| 218 | + ), | |
| 219 | + ), | |
| 220 | + ); | |
| 221 | +}; | |