@tillstack/secrets-node 0.2.1 → 0.3.0

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/dist/index.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { SecretsClientOptions, SecretsClient, PullResult } from '@tillstack/secrets-core';
1
+ import { SecretsClientOptions, BrokerClient, SecretsClient, PullResult } from '@tillstack/secrets-core';
2
2
  export * from '@tillstack/secrets-core';
3
3
 
4
4
  /** Create a client from options or the environment (`TILLSECRETS_TOKEN`,
@@ -11,5 +11,39 @@ interface LoadOptions extends Partial<SecretsClientOptions> {
11
11
  }
12
12
  /** Pull secrets and inject them into process.env. Returns the pulled map. */
13
13
  declare function load(opts?: LoadOptions): Promise<PullResult>;
14
+ interface CreateBrokerOptions {
15
+ /** Force a transport. Default `auto`: use the LOCAL bridge when the process runs
16
+ * under the TillForge bridge daemon (`TILLDEV_BROKER_URL` set) — the strongest
17
+ * posture, the value never leaves the machine — otherwise the cloud broker. */
18
+ mode?: 'auto' | 'bridge' | 'cloud';
19
+ /** Cloud API base (derives the spend endpoint). Ignored in bridge mode.
20
+ * Defaults to `TILLDEV_URL` / `TILLSECRETS_URL` / `https://tilldev.dev`. */
21
+ url?: string;
22
+ /** Bearer token — a session / `tp_` API key (cloud, `TILLDEV_TOKEN`) or the
23
+ * bridge run token (`TILLDEV_BROKER_TOKEN`, injected by the daemon). */
24
+ token?: string;
25
+ /** Stable agent identity. Required in cloud mode (or `TILLDEV_AGENT_KEY`). */
26
+ agentKey?: string;
27
+ /** Session id for session-scoped grants (or `TILLDEV_SESSION`). */
28
+ sessionId?: string;
29
+ timeoutMs?: number;
30
+ fetch?: typeof fetch;
31
+ }
32
+ /**
33
+ * Create a secretless-broker client. In `auto` mode it prefers the local bridge
34
+ * proxy (value spent on the user's machine) when the daemon has injected
35
+ * `TILLDEV_BROKER_URL` + `TILLDEV_BROKER_TOKEN`, and otherwise talks to the cloud
36
+ * broker with a session / `tp_` token + an agent identity.
37
+ *
38
+ * import { createBroker, secretref } from '@tillstack/secrets-node'
39
+ * const broker = createBroker({ agentKey: 'my-job' })
40
+ * const res = await broker.fetch('https://api.stripe.com/v1/charges', {
41
+ * method: 'POST',
42
+ * headers: { authorization: `Bearer ${secretref('prod', 'live', 'STRIPE_KEY')}` },
43
+ * body,
44
+ * })
45
+ * // res.body is the scrubbed reply — the STRIPE_KEY never entered this process.
46
+ */
47
+ declare function createBroker(opts?: CreateBrokerOptions): BrokerClient;
14
48
 
15
- export { type LoadOptions, createClient, load };
49
+ export { type CreateBrokerOptions, type LoadOptions, createBroker, createClient, load };
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { SecretsClientOptions, SecretsClient, PullResult } from '@tillstack/secrets-core';
1
+ import { SecretsClientOptions, BrokerClient, SecretsClient, PullResult } from '@tillstack/secrets-core';
2
2
  export * from '@tillstack/secrets-core';
3
3
 
4
4
  /** Create a client from options or the environment (`TILLSECRETS_TOKEN`,
@@ -11,5 +11,39 @@ interface LoadOptions extends Partial<SecretsClientOptions> {
11
11
  }
12
12
  /** Pull secrets and inject them into process.env. Returns the pulled map. */
13
13
  declare function load(opts?: LoadOptions): Promise<PullResult>;
14
+ interface CreateBrokerOptions {
15
+ /** Force a transport. Default `auto`: use the LOCAL bridge when the process runs
16
+ * under the TillForge bridge daemon (`TILLDEV_BROKER_URL` set) — the strongest
17
+ * posture, the value never leaves the machine — otherwise the cloud broker. */
18
+ mode?: 'auto' | 'bridge' | 'cloud';
19
+ /** Cloud API base (derives the spend endpoint). Ignored in bridge mode.
20
+ * Defaults to `TILLDEV_URL` / `TILLSECRETS_URL` / `https://tilldev.dev`. */
21
+ url?: string;
22
+ /** Bearer token — a session / `tp_` API key (cloud, `TILLDEV_TOKEN`) or the
23
+ * bridge run token (`TILLDEV_BROKER_TOKEN`, injected by the daemon). */
24
+ token?: string;
25
+ /** Stable agent identity. Required in cloud mode (or `TILLDEV_AGENT_KEY`). */
26
+ agentKey?: string;
27
+ /** Session id for session-scoped grants (or `TILLDEV_SESSION`). */
28
+ sessionId?: string;
29
+ timeoutMs?: number;
30
+ fetch?: typeof fetch;
31
+ }
32
+ /**
33
+ * Create a secretless-broker client. In `auto` mode it prefers the local bridge
34
+ * proxy (value spent on the user's machine) when the daemon has injected
35
+ * `TILLDEV_BROKER_URL` + `TILLDEV_BROKER_TOKEN`, and otherwise talks to the cloud
36
+ * broker with a session / `tp_` token + an agent identity.
37
+ *
38
+ * import { createBroker, secretref } from '@tillstack/secrets-node'
39
+ * const broker = createBroker({ agentKey: 'my-job' })
40
+ * const res = await broker.fetch('https://api.stripe.com/v1/charges', {
41
+ * method: 'POST',
42
+ * headers: { authorization: `Bearer ${secretref('prod', 'live', 'STRIPE_KEY')}` },
43
+ * body,
44
+ * })
45
+ * // res.body is the scrubbed reply — the STRIPE_KEY never entered this process.
46
+ */
47
+ declare function createBroker(opts?: CreateBrokerOptions): BrokerClient;
14
48
 
15
- export { type LoadOptions, createClient, load };
49
+ export { type CreateBrokerOptions, type LoadOptions, createBroker, createClient, load };
package/dist/index.js CHANGED
@@ -23,7 +23,35 @@ async function load(opts = {}) {
23
23
  }
24
24
  return result;
25
25
  }
26
+ function createBroker(opts = {}) {
27
+ const bridgeUrl = process.env.TILLDEV_BROKER_URL;
28
+ const bridgeToken = process.env.TILLDEV_BROKER_TOKEN;
29
+ const useBridge = opts.mode === "bridge" || opts.mode !== "cloud" && !!bridgeUrl && !!bridgeToken;
30
+ const built = { endpoint: "", token: "" };
31
+ if (opts.timeoutMs !== void 0) built.timeoutMs = opts.timeoutMs;
32
+ if (opts.fetch) built.fetch = opts.fetch;
33
+ const agentKey = opts.agentKey ?? process.env.TILLDEV_AGENT_KEY;
34
+ if (agentKey) built.agentKey = agentKey;
35
+ const sessionId = opts.sessionId ?? process.env.TILLDEV_SESSION;
36
+ if (sessionId) built.sessionId = sessionId;
37
+ if (useBridge) {
38
+ if (!bridgeUrl || !bridgeToken) {
39
+ throw new secretsCore.SecretsError("TillSecrets broker: bridge mode needs TILLDEV_BROKER_URL + TILLDEV_BROKER_TOKEN");
40
+ }
41
+ built.endpoint = `${bridgeUrl.replace(/\/$/, "")}/spend`;
42
+ built.token = opts.token ?? bridgeToken;
43
+ return new secretsCore.BrokerClient(built);
44
+ }
45
+ const base = (opts.url ?? process.env.TILLDEV_URL ?? process.env.TILLSECRETS_URL ?? "https://tilldev.dev").replace(/\/$/, "");
46
+ const token = opts.token ?? process.env.TILLDEV_TOKEN ?? process.env.TILLSECRETS_BROKER_TOKEN;
47
+ if (!token) throw new secretsCore.SecretsError("TillSecrets broker: no token \u2014 pass one or set TILLDEV_TOKEN");
48
+ if (!built.agentKey) throw new secretsCore.SecretsError("TillSecrets broker: cloud mode needs an agentKey (or TILLDEV_AGENT_KEY)");
49
+ built.endpoint = `${base}/api/secrets/broker/spend`;
50
+ built.token = token;
51
+ return new secretsCore.BrokerClient(built);
52
+ }
26
53
 
54
+ exports.createBroker = createBroker;
27
55
  exports.createClient = createClient;
28
56
  exports.load = load;
29
57
  Object.keys(secretsCore).forEach(function (k) {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"names":["SecretsClient"],"mappings":";;;;;AAgBO,SAAS,aAAa,IAAA,EAAqD;AAChF,EAAA,MAAM,KAAA,GAAQ,IAAA,EAAM,KAAA,IAAS,OAAA,CAAQ,GAAA,CAAI,iBAAA;AACzC,EAAA,IAAI,CAAC,KAAA,EAAO,MAAM,IAAI,MAAM,gEAA2D,CAAA;AACvF,EAAA,MAAM,KAAA,GAA8B,EAAE,KAAA,EAAM;AAC5C,EAAA,MAAM,GAAA,GAAM,IAAA,EAAM,GAAA,IAAO,OAAA,CAAQ,GAAA,CAAI,eAAA;AACrC,EAAA,IAAI,GAAA,QAAW,GAAA,GAAM,GAAA;AACrB,EAAA,MAAM,GAAA,GAAM,IAAA,EAAM,aAAA,IAAiB,OAAA,CAAQ,GAAA,CAAI,eAAA;AAC/C,EAAA,IAAI,GAAA,QAAW,aAAA,GAAgB,GAAA;AAC/B,EAAA,IAAI,IAAA,EAAM,SAAA,KAAc,MAAA,EAAW,KAAA,CAAM,YAAY,IAAA,CAAK,SAAA;AAC1D,EAAA,IAAI,IAAA,EAAM,KAAA,EAAO,KAAA,CAAM,KAAA,GAAQ,IAAA,CAAK,KAAA;AACpC,EAAA,OAAO,IAAIA,0BAAc,KAAK,CAAA;AAChC;AASA,eAAsB,IAAA,CAAK,IAAA,GAAoB,EAAC,EAAwB;AACtE,EAAA,MAAM,MAAA,GAAS,aAAa,IAAI,CAAA;AAChC,EAAA,MAAM,MAAA,GAAS,MAAM,MAAA,CAAO,IAAA,EAAK;AACjC,EAAA,KAAA,MAAW,CAAC,GAAG,CAAC,CAAA,IAAK,OAAO,OAAA,CAAQ,MAAA,CAAO,OAAO,CAAA,EAAG;AACnD,IAAA,IAAI,IAAA,CAAK,QAAA,IAAY,OAAA,CAAQ,GAAA,CAAI,CAAC,MAAM,MAAA,EAAW,OAAA,CAAQ,GAAA,CAAI,CAAC,CAAA,GAAI,CAAA;AAAA,EACtE;AACA,EAAA,OAAO,MAAA;AACT","file":"index.js","sourcesContent":["// @tillstack/secrets-node — TillSecrets client for Node.js.\n//\n// import { load } from '@tillstack/secrets-node'\n// await load() // reads TILLSECRETS_TOKEN, injects into process.env\n// // ... process.env.STRIPE_KEY is now populated\n//\n// or explicitly:\n// const client = createClient({ token })\n// const { secrets } = await client.pull()\n\nimport { SecretsClient, type SecretsClientOptions, type PullResult } from '@tillstack/secrets-core'\n\nexport * from '@tillstack/secrets-core'\n\n/** Create a client from options or the environment (`TILLSECRETS_TOKEN`,\n * optional `TILLSECRETS_URL`, optional `TILLSECRETS_ENV`). */\nexport function createClient(opts?: Partial<SecretsClientOptions>): SecretsClient {\n const token = opts?.token ?? process.env.TILLSECRETS_TOKEN\n if (!token) throw new Error('TillSecrets: no token — pass one or set TILLSECRETS_TOKEN')\n const built: SecretsClientOptions = { token }\n const url = opts?.url ?? process.env.TILLSECRETS_URL\n if (url) built.url = url\n const env = opts?.environmentId ?? process.env.TILLSECRETS_ENV\n if (env) built.environmentId = env\n if (opts?.timeoutMs !== undefined) built.timeoutMs = opts.timeoutMs\n if (opts?.fetch) built.fetch = opts.fetch\n return new SecretsClient(built)\n}\n\nexport interface LoadOptions extends Partial<SecretsClientOptions> {\n /** Overwrite keys already present in process.env (default false — existing\n * wins, matching dotenv). */\n override?: boolean\n}\n\n/** Pull secrets and inject them into process.env. Returns the pulled map. */\nexport async function load(opts: LoadOptions = {}): Promise<PullResult> {\n const client = createClient(opts)\n const result = await client.pull()\n for (const [k, v] of Object.entries(result.secrets)) {\n if (opts.override || process.env[k] === undefined) process.env[k] = v\n }\n return result\n}\n"]}
1
+ {"version":3,"sources":["../src/index.ts"],"names":["SecretsClient","SecretsError","BrokerClient"],"mappings":"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","file":"index.js","sourcesContent":["// @tillstack/secrets-node — TillSecrets client for Node.js.\n//\n// import { load } from '@tillstack/secrets-node'\n// await load() // reads TILLSECRETS_TOKEN, injects into process.env\n// // ... process.env.STRIPE_KEY is now populated\n//\n// or explicitly:\n// const client = createClient({ token })\n// const { secrets } = await client.pull()\n\nimport {\n SecretsClient,\n SecretsError,\n BrokerClient,\n type SecretsClientOptions,\n type PullResult,\n type BrokerClientOptions,\n} from '@tillstack/secrets-core'\n\nexport * from '@tillstack/secrets-core'\n\n/** Create a client from options or the environment (`TILLSECRETS_TOKEN`,\n * optional `TILLSECRETS_URL`, optional `TILLSECRETS_ENV`). */\nexport function createClient(opts?: Partial<SecretsClientOptions>): SecretsClient {\n const token = opts?.token ?? process.env.TILLSECRETS_TOKEN\n if (!token) throw new Error('TillSecrets: no token — pass one or set TILLSECRETS_TOKEN')\n const built: SecretsClientOptions = { token }\n const url = opts?.url ?? process.env.TILLSECRETS_URL\n if (url) built.url = url\n const env = opts?.environmentId ?? process.env.TILLSECRETS_ENV\n if (env) built.environmentId = env\n if (opts?.timeoutMs !== undefined) built.timeoutMs = opts.timeoutMs\n if (opts?.fetch) built.fetch = opts.fetch\n return new SecretsClient(built)\n}\n\nexport interface LoadOptions extends Partial<SecretsClientOptions> {\n /** Overwrite keys already present in process.env (default false — existing\n * wins, matching dotenv). */\n override?: boolean\n}\n\n/** Pull secrets and inject them into process.env. Returns the pulled map. */\nexport async function load(opts: LoadOptions = {}): Promise<PullResult> {\n const client = createClient(opts)\n const result = await client.pull()\n for (const [k, v] of Object.entries(result.secrets)) {\n if (opts.override || process.env[k] === undefined) process.env[k] = v\n }\n return result\n}\n\nexport interface CreateBrokerOptions {\n /** Force a transport. Default `auto`: use the LOCAL bridge when the process runs\n * under the TillForge bridge daemon (`TILLDEV_BROKER_URL` set) — the strongest\n * posture, the value never leaves the machine — otherwise the cloud broker. */\n mode?: 'auto' | 'bridge' | 'cloud'\n /** Cloud API base (derives the spend endpoint). Ignored in bridge mode.\n * Defaults to `TILLDEV_URL` / `TILLSECRETS_URL` / `https://tilldev.dev`. */\n url?: string\n /** Bearer token — a session / `tp_` API key (cloud, `TILLDEV_TOKEN`) or the\n * bridge run token (`TILLDEV_BROKER_TOKEN`, injected by the daemon). */\n token?: string\n /** Stable agent identity. Required in cloud mode (or `TILLDEV_AGENT_KEY`). */\n agentKey?: string\n /** Session id for session-scoped grants (or `TILLDEV_SESSION`). */\n sessionId?: string\n timeoutMs?: number\n fetch?: typeof fetch\n}\n\n/**\n * Create a secretless-broker client. In `auto` mode it prefers the local bridge\n * proxy (value spent on the user's machine) when the daemon has injected\n * `TILLDEV_BROKER_URL` + `TILLDEV_BROKER_TOKEN`, and otherwise talks to the cloud\n * broker with a session / `tp_` token + an agent identity.\n *\n * import { createBroker, secretref } from '@tillstack/secrets-node'\n * const broker = createBroker({ agentKey: 'my-job' })\n * const res = await broker.fetch('https://api.stripe.com/v1/charges', {\n * method: 'POST',\n * headers: { authorization: `Bearer ${secretref('prod', 'live', 'STRIPE_KEY')}` },\n * body,\n * })\n * // res.body is the scrubbed reply — the STRIPE_KEY never entered this process.\n */\nexport function createBroker(opts: CreateBrokerOptions = {}): BrokerClient {\n const bridgeUrl = process.env.TILLDEV_BROKER_URL\n const bridgeToken = process.env.TILLDEV_BROKER_TOKEN\n const useBridge = opts.mode === 'bridge' || (opts.mode !== 'cloud' && !!bridgeUrl && !!bridgeToken)\n\n const built: BrokerClientOptions = { endpoint: '', token: '' }\n if (opts.timeoutMs !== undefined) built.timeoutMs = opts.timeoutMs\n if (opts.fetch) built.fetch = opts.fetch\n const agentKey = opts.agentKey ?? process.env.TILLDEV_AGENT_KEY\n if (agentKey) built.agentKey = agentKey\n const sessionId = opts.sessionId ?? process.env.TILLDEV_SESSION\n if (sessionId) built.sessionId = sessionId\n\n if (useBridge) {\n if (!bridgeUrl || !bridgeToken) {\n throw new SecretsError('TillSecrets broker: bridge mode needs TILLDEV_BROKER_URL + TILLDEV_BROKER_TOKEN')\n }\n built.endpoint = `${bridgeUrl.replace(/\\/$/, '')}/spend`\n built.token = opts.token ?? bridgeToken\n return new BrokerClient(built)\n }\n\n const base = (opts.url ?? process.env.TILLDEV_URL ?? process.env.TILLSECRETS_URL ?? 'https://tilldev.dev').replace(/\\/$/, '')\n const token = opts.token ?? process.env.TILLDEV_TOKEN ?? process.env.TILLSECRETS_BROKER_TOKEN\n if (!token) throw new SecretsError('TillSecrets broker: no token — pass one or set TILLDEV_TOKEN')\n if (!built.agentKey) throw new SecretsError('TillSecrets broker: cloud mode needs an agentKey (or TILLDEV_AGENT_KEY)')\n built.endpoint = `${base}/api/secrets/broker/spend`\n built.token = token\n return new BrokerClient(built)\n}\n"]}
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { SecretsClient } from '@tillstack/secrets-core';
1
+ import { SecretsClient, SecretsError, BrokerClient } from '@tillstack/secrets-core';
2
2
  export * from '@tillstack/secrets-core';
3
3
 
4
4
  // src/index.ts
@@ -22,7 +22,34 @@ async function load(opts = {}) {
22
22
  }
23
23
  return result;
24
24
  }
25
+ function createBroker(opts = {}) {
26
+ const bridgeUrl = process.env.TILLDEV_BROKER_URL;
27
+ const bridgeToken = process.env.TILLDEV_BROKER_TOKEN;
28
+ const useBridge = opts.mode === "bridge" || opts.mode !== "cloud" && !!bridgeUrl && !!bridgeToken;
29
+ const built = { endpoint: "", token: "" };
30
+ if (opts.timeoutMs !== void 0) built.timeoutMs = opts.timeoutMs;
31
+ if (opts.fetch) built.fetch = opts.fetch;
32
+ const agentKey = opts.agentKey ?? process.env.TILLDEV_AGENT_KEY;
33
+ if (agentKey) built.agentKey = agentKey;
34
+ const sessionId = opts.sessionId ?? process.env.TILLDEV_SESSION;
35
+ if (sessionId) built.sessionId = sessionId;
36
+ if (useBridge) {
37
+ if (!bridgeUrl || !bridgeToken) {
38
+ throw new SecretsError("TillSecrets broker: bridge mode needs TILLDEV_BROKER_URL + TILLDEV_BROKER_TOKEN");
39
+ }
40
+ built.endpoint = `${bridgeUrl.replace(/\/$/, "")}/spend`;
41
+ built.token = opts.token ?? bridgeToken;
42
+ return new BrokerClient(built);
43
+ }
44
+ const base = (opts.url ?? process.env.TILLDEV_URL ?? process.env.TILLSECRETS_URL ?? "https://tilldev.dev").replace(/\/$/, "");
45
+ const token = opts.token ?? process.env.TILLDEV_TOKEN ?? process.env.TILLSECRETS_BROKER_TOKEN;
46
+ if (!token) throw new SecretsError("TillSecrets broker: no token \u2014 pass one or set TILLDEV_TOKEN");
47
+ if (!built.agentKey) throw new SecretsError("TillSecrets broker: cloud mode needs an agentKey (or TILLDEV_AGENT_KEY)");
48
+ built.endpoint = `${base}/api/secrets/broker/spend`;
49
+ built.token = token;
50
+ return new BrokerClient(built);
51
+ }
25
52
 
26
- export { createClient, load };
53
+ export { createBroker, createClient, load };
27
54
  //# sourceMappingURL=index.mjs.map
28
55
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"names":[],"mappings":";;;;AAgBO,SAAS,aAAa,IAAA,EAAqD;AAChF,EAAA,MAAM,KAAA,GAAQ,IAAA,EAAM,KAAA,IAAS,OAAA,CAAQ,GAAA,CAAI,iBAAA;AACzC,EAAA,IAAI,CAAC,KAAA,EAAO,MAAM,IAAI,MAAM,gEAA2D,CAAA;AACvF,EAAA,MAAM,KAAA,GAA8B,EAAE,KAAA,EAAM;AAC5C,EAAA,MAAM,GAAA,GAAM,IAAA,EAAM,GAAA,IAAO,OAAA,CAAQ,GAAA,CAAI,eAAA;AACrC,EAAA,IAAI,GAAA,QAAW,GAAA,GAAM,GAAA;AACrB,EAAA,MAAM,GAAA,GAAM,IAAA,EAAM,aAAA,IAAiB,OAAA,CAAQ,GAAA,CAAI,eAAA;AAC/C,EAAA,IAAI,GAAA,QAAW,aAAA,GAAgB,GAAA;AAC/B,EAAA,IAAI,IAAA,EAAM,SAAA,KAAc,MAAA,EAAW,KAAA,CAAM,YAAY,IAAA,CAAK,SAAA;AAC1D,EAAA,IAAI,IAAA,EAAM,KAAA,EAAO,KAAA,CAAM,KAAA,GAAQ,IAAA,CAAK,KAAA;AACpC,EAAA,OAAO,IAAI,cAAc,KAAK,CAAA;AAChC;AASA,eAAsB,IAAA,CAAK,IAAA,GAAoB,EAAC,EAAwB;AACtE,EAAA,MAAM,MAAA,GAAS,aAAa,IAAI,CAAA;AAChC,EAAA,MAAM,MAAA,GAAS,MAAM,MAAA,CAAO,IAAA,EAAK;AACjC,EAAA,KAAA,MAAW,CAAC,GAAG,CAAC,CAAA,IAAK,OAAO,OAAA,CAAQ,MAAA,CAAO,OAAO,CAAA,EAAG;AACnD,IAAA,IAAI,IAAA,CAAK,QAAA,IAAY,OAAA,CAAQ,GAAA,CAAI,CAAC,MAAM,MAAA,EAAW,OAAA,CAAQ,GAAA,CAAI,CAAC,CAAA,GAAI,CAAA;AAAA,EACtE;AACA,EAAA,OAAO,MAAA;AACT","file":"index.mjs","sourcesContent":["// @tillstack/secrets-node — TillSecrets client for Node.js.\n//\n// import { load } from '@tillstack/secrets-node'\n// await load() // reads TILLSECRETS_TOKEN, injects into process.env\n// // ... process.env.STRIPE_KEY is now populated\n//\n// or explicitly:\n// const client = createClient({ token })\n// const { secrets } = await client.pull()\n\nimport { SecretsClient, type SecretsClientOptions, type PullResult } from '@tillstack/secrets-core'\n\nexport * from '@tillstack/secrets-core'\n\n/** Create a client from options or the environment (`TILLSECRETS_TOKEN`,\n * optional `TILLSECRETS_URL`, optional `TILLSECRETS_ENV`). */\nexport function createClient(opts?: Partial<SecretsClientOptions>): SecretsClient {\n const token = opts?.token ?? process.env.TILLSECRETS_TOKEN\n if (!token) throw new Error('TillSecrets: no token — pass one or set TILLSECRETS_TOKEN')\n const built: SecretsClientOptions = { token }\n const url = opts?.url ?? process.env.TILLSECRETS_URL\n if (url) built.url = url\n const env = opts?.environmentId ?? process.env.TILLSECRETS_ENV\n if (env) built.environmentId = env\n if (opts?.timeoutMs !== undefined) built.timeoutMs = opts.timeoutMs\n if (opts?.fetch) built.fetch = opts.fetch\n return new SecretsClient(built)\n}\n\nexport interface LoadOptions extends Partial<SecretsClientOptions> {\n /** Overwrite keys already present in process.env (default false — existing\n * wins, matching dotenv). */\n override?: boolean\n}\n\n/** Pull secrets and inject them into process.env. Returns the pulled map. */\nexport async function load(opts: LoadOptions = {}): Promise<PullResult> {\n const client = createClient(opts)\n const result = await client.pull()\n for (const [k, v] of Object.entries(result.secrets)) {\n if (opts.override || process.env[k] === undefined) process.env[k] = v\n }\n return result\n}\n"]}
1
+ {"version":3,"sources":["../src/index.ts"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["// @tillstack/secrets-node — TillSecrets client for Node.js.\n//\n// import { load } from '@tillstack/secrets-node'\n// await load() // reads TILLSECRETS_TOKEN, injects into process.env\n// // ... process.env.STRIPE_KEY is now populated\n//\n// or explicitly:\n// const client = createClient({ token })\n// const { secrets } = await client.pull()\n\nimport {\n SecretsClient,\n SecretsError,\n BrokerClient,\n type SecretsClientOptions,\n type PullResult,\n type BrokerClientOptions,\n} from '@tillstack/secrets-core'\n\nexport * from '@tillstack/secrets-core'\n\n/** Create a client from options or the environment (`TILLSECRETS_TOKEN`,\n * optional `TILLSECRETS_URL`, optional `TILLSECRETS_ENV`). */\nexport function createClient(opts?: Partial<SecretsClientOptions>): SecretsClient {\n const token = opts?.token ?? process.env.TILLSECRETS_TOKEN\n if (!token) throw new Error('TillSecrets: no token — pass one or set TILLSECRETS_TOKEN')\n const built: SecretsClientOptions = { token }\n const url = opts?.url ?? process.env.TILLSECRETS_URL\n if (url) built.url = url\n const env = opts?.environmentId ?? process.env.TILLSECRETS_ENV\n if (env) built.environmentId = env\n if (opts?.timeoutMs !== undefined) built.timeoutMs = opts.timeoutMs\n if (opts?.fetch) built.fetch = opts.fetch\n return new SecretsClient(built)\n}\n\nexport interface LoadOptions extends Partial<SecretsClientOptions> {\n /** Overwrite keys already present in process.env (default false — existing\n * wins, matching dotenv). */\n override?: boolean\n}\n\n/** Pull secrets and inject them into process.env. Returns the pulled map. */\nexport async function load(opts: LoadOptions = {}): Promise<PullResult> {\n const client = createClient(opts)\n const result = await client.pull()\n for (const [k, v] of Object.entries(result.secrets)) {\n if (opts.override || process.env[k] === undefined) process.env[k] = v\n }\n return result\n}\n\nexport interface CreateBrokerOptions {\n /** Force a transport. Default `auto`: use the LOCAL bridge when the process runs\n * under the TillForge bridge daemon (`TILLDEV_BROKER_URL` set) — the strongest\n * posture, the value never leaves the machine — otherwise the cloud broker. */\n mode?: 'auto' | 'bridge' | 'cloud'\n /** Cloud API base (derives the spend endpoint). Ignored in bridge mode.\n * Defaults to `TILLDEV_URL` / `TILLSECRETS_URL` / `https://tilldev.dev`. */\n url?: string\n /** Bearer token — a session / `tp_` API key (cloud, `TILLDEV_TOKEN`) or the\n * bridge run token (`TILLDEV_BROKER_TOKEN`, injected by the daemon). */\n token?: string\n /** Stable agent identity. Required in cloud mode (or `TILLDEV_AGENT_KEY`). */\n agentKey?: string\n /** Session id for session-scoped grants (or `TILLDEV_SESSION`). */\n sessionId?: string\n timeoutMs?: number\n fetch?: typeof fetch\n}\n\n/**\n * Create a secretless-broker client. In `auto` mode it prefers the local bridge\n * proxy (value spent on the user's machine) when the daemon has injected\n * `TILLDEV_BROKER_URL` + `TILLDEV_BROKER_TOKEN`, and otherwise talks to the cloud\n * broker with a session / `tp_` token + an agent identity.\n *\n * import { createBroker, secretref } from '@tillstack/secrets-node'\n * const broker = createBroker({ agentKey: 'my-job' })\n * const res = await broker.fetch('https://api.stripe.com/v1/charges', {\n * method: 'POST',\n * headers: { authorization: `Bearer ${secretref('prod', 'live', 'STRIPE_KEY')}` },\n * body,\n * })\n * // res.body is the scrubbed reply — the STRIPE_KEY never entered this process.\n */\nexport function createBroker(opts: CreateBrokerOptions = {}): BrokerClient {\n const bridgeUrl = process.env.TILLDEV_BROKER_URL\n const bridgeToken = process.env.TILLDEV_BROKER_TOKEN\n const useBridge = opts.mode === 'bridge' || (opts.mode !== 'cloud' && !!bridgeUrl && !!bridgeToken)\n\n const built: BrokerClientOptions = { endpoint: '', token: '' }\n if (opts.timeoutMs !== undefined) built.timeoutMs = opts.timeoutMs\n if (opts.fetch) built.fetch = opts.fetch\n const agentKey = opts.agentKey ?? process.env.TILLDEV_AGENT_KEY\n if (agentKey) built.agentKey = agentKey\n const sessionId = opts.sessionId ?? process.env.TILLDEV_SESSION\n if (sessionId) built.sessionId = sessionId\n\n if (useBridge) {\n if (!bridgeUrl || !bridgeToken) {\n throw new SecretsError('TillSecrets broker: bridge mode needs TILLDEV_BROKER_URL + TILLDEV_BROKER_TOKEN')\n }\n built.endpoint = `${bridgeUrl.replace(/\\/$/, '')}/spend`\n built.token = opts.token ?? bridgeToken\n return new BrokerClient(built)\n }\n\n const base = (opts.url ?? process.env.TILLDEV_URL ?? process.env.TILLSECRETS_URL ?? 'https://tilldev.dev').replace(/\\/$/, '')\n const token = opts.token ?? process.env.TILLDEV_TOKEN ?? process.env.TILLSECRETS_BROKER_TOKEN\n if (!token) throw new SecretsError('TillSecrets broker: no token — pass one or set TILLDEV_TOKEN')\n if (!built.agentKey) throw new SecretsError('TillSecrets broker: cloud mode needs an agentKey (or TILLDEV_AGENT_KEY)')\n built.endpoint = `${base}/api/secrets/broker/spend`\n built.token = token\n return new BrokerClient(built)\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tillstack/secrets-node",
3
- "version": "0.2.1",
3
+ "version": "0.3.0",
4
4
  "description": "TillSecrets client for Node.js — pull encrypted config at boot and inject it into process.env, with a drop-in dotenv-style API.",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
@@ -24,7 +24,7 @@
24
24
  "dist"
25
25
  ],
26
26
  "dependencies": {
27
- "@tillstack/secrets-core": "^0.2.1"
27
+ "@tillstack/secrets-core": "^0.3.0"
28
28
  },
29
29
  "devDependencies": {
30
30
  "@types/node": "^22.0.0",