@introspection-sdk/introspection-node 0.13.0 → 0.14.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.
@@ -1,4 +1,4 @@
1
1
 
2
- > @introspection-sdk/introspection-node@0.13.0 build /home/runner/work/introspection-js-sdk/introspection-js-sdk/packages/introspection-node
2
+ > @introspection-sdk/introspection-node@0.14.0 build /home/runner/work/introspection-js-sdk/introspection-js-sdk/packages/introspection-node
3
3
  > tsc
4
4
 
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAEhE,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,YAAY,CAAC;AAC7D,OAAO,EAAuB,KAAK,yBAAyB,EAAE,MAAM,WAAW,CAAC;AAChF,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,OAAO,EAEL,KAAK,oBAAoB,EACzB,KAAK,WAAW,EACjB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAEL,KAAK,uBAAuB,EAC5B,KAAK,cAAc,EACpB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAAiB,KAAK,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAExE;;;;;;;;;;;;;;;;;;;GAmBG;AACH,qBAAa,mBAAmB;IAC9B,2EAA2E;IAC3E,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC;IAC5B,mFAAmF;IACnF,QAAQ,CAAC,eAAe,EAAE,eAAe,CAAC;IAE1C;;;;OAIG;IACH,QAAQ,CAAC,QAAQ,EAAE,WAAW,GAAG,oBAAoB,CAAC;IAEtD;;OAEG;IACH,QAAQ,CAAC,WAAW,EAAE,cAAc,GAAG,uBAAuB,CAAC;IAE/D;;;;OAIG;IACH,QAAQ,CAAC,OAAO,EAAE,UAAU,CAAC;gBAEjB,OAAO,GAAE,0BAA+B;IAgCpD;;;;;;;;;;;;;;;;;;;;;;;;;OAyBG;WACU,kBAAkB,CAC7B,MAAM,EAAE,yBAAyB,GAAG;QAAE,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,GAC3D,OAAO,CAAC,mBAAmB,CAAC;IAS/B,wCAAwC;IAClC,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;CAKhC"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAEhE,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,YAAY,CAAC;AAC7D,OAAO,EAAuB,KAAK,yBAAyB,EAAE,MAAM,WAAW,CAAC;AAChF,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,OAAO,EAEL,KAAK,oBAAoB,EACzB,KAAK,WAAW,EACjB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAEL,KAAK,uBAAuB,EAC5B,KAAK,cAAc,EACpB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAAiB,KAAK,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAGxE;;;;;;;;;;;;;;;;;;;GAmBG;AACH,qBAAa,mBAAmB;IAC9B,2EAA2E;IAC3E,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC;IAC5B,mFAAmF;IACnF,QAAQ,CAAC,eAAe,EAAE,eAAe,CAAC;IAE1C;;;;OAIG;IACH,QAAQ,CAAC,QAAQ,EAAE,WAAW,GAAG,oBAAoB,CAAC;IAEtD;;OAEG;IACH,QAAQ,CAAC,WAAW,EAAE,cAAc,GAAG,uBAAuB,CAAC;IAE/D;;;;OAIG;IACH,QAAQ,CAAC,OAAO,EAAE,UAAU,CAAC;gBAEjB,OAAO,GAAE,0BAA+B;IA0CpD;;;;;;;;;;;;;;;;;;;;;;;;;OAyBG;WACU,kBAAkB,CAC7B,MAAM,EAAE,yBAAyB,GAAG;QAAE,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,GAC3D,OAAO,CAAC,mBAAmB,CAAC;IAS/B,wCAAwC;IAClC,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;CAKhC"}
package/dist/client.js CHANGED
@@ -17,6 +17,7 @@ import { HttpClient } from "./http.js";
17
17
  import { attachRuntimes, } from "./resources/runtimes.js";
18
18
  import { attachExperiments, } from "./resources/experiments.js";
19
19
  import { attachRecipes } from "./resources/recipes.js";
20
+ import { DEV_TARGET_HEADER, resolveDevTarget } from "./dev-target.js";
20
21
  /**
21
22
  * Introspection REST client.
22
23
  *
@@ -61,20 +62,29 @@ export class IntrospectionClient {
61
62
  constructor(options = {}) {
62
63
  const token = options.token || process.env.INTROSPECTION_TOKEN || "";
63
64
  const advanced = options.advanced || {};
64
- this.advancedOptions = advanced;
65
65
  const baseApiUrl = advanced.baseApiUrl ||
66
66
  process.env.INTROSPECTION_BASE_API_URL ||
67
67
  "https://api.introspection.dev";
68
68
  if (!token) {
69
69
  sdkLogger.warn("IntrospectionClient: No token provided. REST calls will fail.");
70
70
  }
71
+ // INTROSPECTION_DEV_TARGET rides every request as a header so it reaches
72
+ // the paths a runner cannot: a bare `POST /v1/tasks` with a dev API key
73
+ // mints its JWT from the key row and has no per-request claim to carry.
74
+ // Merged first, so an explicit `additionalHeaders` entry still wins, and
75
+ // stored on advancedOptions so the Runner's own DP client inherits it.
76
+ const devTarget = resolveDevTarget();
77
+ const additionalHeaders = devTarget
78
+ ? { [DEV_TARGET_HEADER]: devTarget, ...advanced.additionalHeaders }
79
+ : advanced.additionalHeaders;
80
+ this.advancedOptions = { ...advanced, additionalHeaders };
71
81
  // CP HTTP client — talks to the customer-facing API with the customer
72
82
  // API key. Runners get their own HttpClient instances pointed at the
73
83
  // `deployment.endpoint` returned by `/v1/runtimes/{id}/run`.
74
84
  this.cpHttp = new HttpClient({
75
85
  apiUrl: baseApiUrl,
76
86
  token,
77
- additionalHeaders: advanced.additionalHeaders,
87
+ additionalHeaders: this.advancedOptions.additionalHeaders,
78
88
  fetch: advanced.fetch,
79
89
  });
80
90
  this.runtimes = attachRuntimes(this, this.cpHttp);
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAGH,OAAO,EAAE,MAAM,IAAI,SAAS,EAAE,MAAM,YAAY,CAAC;AAEjD,OAAO,EAAE,mBAAmB,EAAkC,MAAM,WAAW,CAAC;AAChF,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,OAAO,EACL,cAAc,GAGf,MAAM,yBAAyB,CAAC;AACjC,OAAO,EACL,iBAAiB,GAGlB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAAE,aAAa,EAAmB,MAAM,wBAAwB,CAAC;AAExE;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,OAAO,mBAAmB;IAC9B,2EAA2E;IAClE,MAAM,CAAa;IAC5B,mFAAmF;IAC1E,eAAe,CAAkB;IAE1C;;;;OAIG;IACM,QAAQ,CAAqC;IAEtD;;OAEG;IACM,WAAW,CAA2C;IAE/D;;;;OAIG;IACM,OAAO,CAAa;IAE7B,YAAY,UAAsC,EAAE;QAClD,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,OAAO,CAAC,GAAG,CAAC,mBAAmB,IAAI,EAAE,CAAC;QACrE,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,EAAE,CAAC;QACxC,IAAI,CAAC,eAAe,GAAG,QAAQ,CAAC;QAChC,MAAM,UAAU,GACd,QAAQ,CAAC,UAAU;YACnB,OAAO,CAAC,GAAG,CAAC,0BAA0B;YACtC,+BAA+B,CAAC;QAElC,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,SAAS,CAAC,IAAI,CACZ,+DAA+D,CAChE,CAAC;QACJ,CAAC;QAED,sEAAsE;QACtE,qEAAqE;QACrE,6DAA6D;QAC7D,IAAI,CAAC,MAAM,GAAG,IAAI,UAAU,CAAC;YAC3B,MAAM,EAAE,UAAU;YAClB,KAAK;YACL,iBAAiB,EAAE,QAAQ,CAAC,iBAAiB;YAC7C,KAAK,EAAE,QAAQ,CAAC,KAAK;SACtB,CAAC,CAAC;QAEH,IAAI,CAAC,QAAQ,GAAG,cAAc,CAAC,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;QAClD,IAAI,CAAC,WAAW,GAAG,iBAAiB,CAAC,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;QACxD,IAAI,CAAC,OAAO,GAAG,aAAa,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAE1C,SAAS,CAAC,IAAI,CAAC,wCAAwC,UAAU,EAAE,CAAC,CAAC;IACvE,CAAC;IAED;;;;;;;;;;;;;;;;;;;;;;;;;OAyBG;IACH,MAAM,CAAC,KAAK,CAAC,kBAAkB,CAC7B,MAA4D;QAE5D,MAAM,EAAE,YAAY,EAAE,GAAG,MAAM,mBAAmB,CAAC,MAAM,CAAC,CAAC;QAC3D,OAAO,IAAI,mBAAmB,CAAC;YAC7B,KAAK,EAAE,YAAY;YACnB,WAAW,EAAE,MAAM,CAAC,WAAW;YAC/B,QAAQ,EAAE,EAAE,UAAU,EAAE,MAAM,CAAC,UAAU,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE;SACjE,CAAC,CAAC;IACL,CAAC;IAED,wCAAwC;IACxC,KAAK,CAAC,QAAQ;QACZ,kEAAkE;QAClE,gDAAgD;QAChD,SAAS,CAAC,KAAK,CAAC,uCAAuC,CAAC,CAAC;IAC3D,CAAC;CACF"}
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Development-target resolution — which `introspection dev` server this
3
+ * process's tasks should reach.
4
+ *
5
+ * Two developers can run `introspection dev` against one shared Runtime. A
6
+ * task created by a shared application credential carries no developer, so the
7
+ * platform cannot tell their machines apart; the caller names one instead.
8
+ * `introspection dev` prints the value to set:
9
+ *
10
+ * ```
11
+ * serving as: roland
12
+ * for your app: INTROSPECTION_DEV_TARGET=roland
13
+ * ```
14
+ *
15
+ * Carried as a header rather than on the runner's `caller` payload: `caller`
16
+ * is descriptive metadata the platform never acts on, and a target is a
17
+ * per-request selector the platform does act on. Keeping them apart is what
18
+ * lets `caller` stay a free-form bag, and it is the only transport that
19
+ * reaches a bare `POST /v1/tasks` with a dev API key, whose JWT is minted from
20
+ * the key row with no per-request input path.
21
+ *
22
+ * Deliberately env-only, with no `os.userInfo()` fallback. Defaulting to the
23
+ * local username would be zero-config on a laptop and wrong everywhere else: a
24
+ * process running in a shared development deployment under an account like
25
+ * `node` would silently name a machine nobody is serving and fail closed,
26
+ * where today it reaches the one connected dev server. The CLI defaults to the
27
+ * username because it is naming *itself* and always runs on the developer's
28
+ * machine; this names *someone else's* machine and can run anywhere.
29
+ *
30
+ * Inert outside development: the Data Plane consults a target only on the
31
+ * development pin path, so a stray value in staging or production is ignored.
32
+ */
33
+ /** Header carrying the target on requests that have no runner to ride. */
34
+ export declare const DEV_TARGET_HEADER = "x-introspection-dev-target";
35
+ /** The env var `introspection dev` prints and both the CLI and SDK read. */
36
+ export declare const DEV_TARGET_ENV = "INTROSPECTION_DEV_TARGET";
37
+ /**
38
+ * The development target for this process, or `undefined` when unset.
39
+ *
40
+ * Percent-encoded, because the value becomes an HTTP header and a header is
41
+ * bytes: a login name like `andré` is not transmissible as-is, and a runtime
42
+ * that lets it through sends latin-1 bytes the server would read back as a
43
+ * different string. Encoding here is lossless and costs nothing for the
44
+ * ordinary ASCII name, which encodes to itself.
45
+ *
46
+ * Safe to send encoded because the Data Plane decodes before it normalizes,
47
+ * so `andré` and `andr%C3%A9` land on the same target as the `--as andré`
48
+ * the CLI advertises over protobuf, where no encoding is needed.
49
+ *
50
+ * Read through `globalThis.process` so the module stays importable from
51
+ * non-Node runtimes that share this package's build.
52
+ */
53
+ export declare function resolveDevTarget(): string | undefined;
54
+ //# sourceMappingURL=dev-target.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dev-target.d.ts","sourceRoot":"","sources":["../src/dev-target.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,0EAA0E;AAC1E,eAAO,MAAM,iBAAiB,+BAA+B,CAAC;AAE9D,4EAA4E;AAC5E,eAAO,MAAM,cAAc,6BAA6B,CAAC;AAkBzD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,gBAAgB,IAAI,MAAM,GAAG,SAAS,CAOrD"}
@@ -0,0 +1,71 @@
1
+ /**
2
+ * Development-target resolution — which `introspection dev` server this
3
+ * process's tasks should reach.
4
+ *
5
+ * Two developers can run `introspection dev` against one shared Runtime. A
6
+ * task created by a shared application credential carries no developer, so the
7
+ * platform cannot tell their machines apart; the caller names one instead.
8
+ * `introspection dev` prints the value to set:
9
+ *
10
+ * ```
11
+ * serving as: roland
12
+ * for your app: INTROSPECTION_DEV_TARGET=roland
13
+ * ```
14
+ *
15
+ * Carried as a header rather than on the runner's `caller` payload: `caller`
16
+ * is descriptive metadata the platform never acts on, and a target is a
17
+ * per-request selector the platform does act on. Keeping them apart is what
18
+ * lets `caller` stay a free-form bag, and it is the only transport that
19
+ * reaches a bare `POST /v1/tasks` with a dev API key, whose JWT is minted from
20
+ * the key row with no per-request input path.
21
+ *
22
+ * Deliberately env-only, with no `os.userInfo()` fallback. Defaulting to the
23
+ * local username would be zero-config on a laptop and wrong everywhere else: a
24
+ * process running in a shared development deployment under an account like
25
+ * `node` would silently name a machine nobody is serving and fail closed,
26
+ * where today it reaches the one connected dev server. The CLI defaults to the
27
+ * username because it is naming *itself* and always runs on the developer's
28
+ * machine; this names *someone else's* machine and can run anywhere.
29
+ *
30
+ * Inert outside development: the Data Plane consults a target only on the
31
+ * development pin path, so a stray value in staging or production is ignored.
32
+ */
33
+ /** Header carrying the target on requests that have no runner to ride. */
34
+ export const DEV_TARGET_HEADER = "x-introspection-dev-target";
35
+ /** The env var `introspection dev` prints and both the CLI and SDK read. */
36
+ export const DEV_TARGET_ENV = "INTROSPECTION_DEV_TARGET";
37
+ /**
38
+ * Percent-encode to RFC 3986, so the three SDKs put identical bytes on the
39
+ * wire for the same target.
40
+ *
41
+ * `encodeURIComponent` leaves `!'()*` alone where Python's `quote(safe="")`
42
+ * and the Rust client encode them. The Data Plane decodes before it
43
+ * normalizes, so either form routes — but a header that differs by which
44
+ * client sent it is a debugging trap for no benefit.
45
+ */
46
+ function encodeTarget(value) {
47
+ return encodeURIComponent(value).replace(/[!'()*]/g, (c) => `%${c.charCodeAt(0).toString(16).toUpperCase()}`);
48
+ }
49
+ /**
50
+ * The development target for this process, or `undefined` when unset.
51
+ *
52
+ * Percent-encoded, because the value becomes an HTTP header and a header is
53
+ * bytes: a login name like `andré` is not transmissible as-is, and a runtime
54
+ * that lets it through sends latin-1 bytes the server would read back as a
55
+ * different string. Encoding here is lossless and costs nothing for the
56
+ * ordinary ASCII name, which encodes to itself.
57
+ *
58
+ * Safe to send encoded because the Data Plane decodes before it normalizes,
59
+ * so `andré` and `andr%C3%A9` land on the same target as the `--as andré`
60
+ * the CLI advertises over protobuf, where no encoding is needed.
61
+ *
62
+ * Read through `globalThis.process` so the module stays importable from
63
+ * non-Node runtimes that share this package's build.
64
+ */
65
+ export function resolveDevTarget() {
66
+ const env = globalThis.process?.env;
67
+ const raw = env?.[DEV_TARGET_ENV];
68
+ const trimmed = raw?.trim();
69
+ return trimmed ? encodeTarget(trimmed) : undefined;
70
+ }
71
+ //# sourceMappingURL=dev-target.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dev-target.js","sourceRoot":"","sources":["../src/dev-target.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,0EAA0E;AAC1E,MAAM,CAAC,MAAM,iBAAiB,GAAG,4BAA4B,CAAC;AAE9D,4EAA4E;AAC5E,MAAM,CAAC,MAAM,cAAc,GAAG,0BAA0B,CAAC;AAEzD;;;;;;;;GAQG;AACH,SAAS,YAAY,CAAC,KAAa;IACjC,OAAO,kBAAkB,CAAC,KAAK,CAAC,CAAC,OAAO,CACtC,UAAU,EACV,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,WAAW,EAAE,EAAE,CACxD,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,gBAAgB;IAC9B,MAAM,GAAG,GACP,UACD,CAAC,OAAO,EAAE,GAAG,CAAC;IACf,MAAM,GAAG,GAAG,GAAG,EAAE,CAAC,cAAc,CAAC,CAAC;IAClC,MAAM,OAAO,GAAG,GAAG,EAAE,IAAI,EAAE,CAAC;IAC5B,OAAO,OAAO,CAAC,CAAC,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AACrD,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@introspection-sdk/introspection-node",
3
- "version": "0.13.0",
3
+ "version": "0.14.0",
4
4
  "license": "Apache-2.0",
5
5
  "description": "Introspection observability SDK for Node.js",
6
6
  "engines": {
@@ -32,29 +32,29 @@
32
32
  }
33
33
  },
34
34
  "devDependencies": {
35
- "@anthropic-ai/claude-agent-sdk": "^0.3.215",
36
- "@anthropic-ai/sdk": "^0.112.3",
35
+ "@anthropic-ai/claude-agent-sdk": "^0.3.220",
36
+ "@anthropic-ai/sdk": "^0.115.0",
37
37
  "@earendil-works/pi-agent-core": "^0.80.10",
38
38
  "@earendil-works/pi-ai": "^0.80.10",
39
- "@google/genai": "^2.12.0",
39
+ "@google/genai": "^2.13.0",
40
40
  "@langchain/core": "^1.2.3",
41
- "@mastra/core": "^1.51.0",
42
- "@mastra/observability": "^1.16.1",
41
+ "@mastra/core": "^1.52.1",
42
+ "@mastra/observability": "^1.16.2",
43
43
  "@openai/agents": "^0.13.5",
44
- "@opentelemetry/api-logs": "^0.220.0",
45
- "@opentelemetry/context-async-hooks": "^2.9.0",
46
- "@opentelemetry/core": "^2.9.0",
47
- "@opentelemetry/exporter-logs-otlp-proto": "^0.220.0",
48
- "@opentelemetry/exporter-trace-otlp-proto": "^0.220.0",
49
- "@opentelemetry/resources": "^2.9.0",
50
- "@opentelemetry/sdk-logs": "^0.220.0",
51
- "@opentelemetry/sdk-trace-base": "^2.9.0",
52
- "@opentelemetry/sdk-trace-node": "^2.9.0",
44
+ "@opentelemetry/api-logs": "^0.221.0",
45
+ "@opentelemetry/context-async-hooks": "^2.10.0",
46
+ "@opentelemetry/core": "^2.10.0",
47
+ "@opentelemetry/exporter-logs-otlp-proto": "^0.221.0",
48
+ "@opentelemetry/exporter-trace-otlp-proto": "^0.221.0",
49
+ "@opentelemetry/resources": "^2.10.0",
50
+ "@opentelemetry/sdk-logs": "^0.221.0",
51
+ "@opentelemetry/sdk-trace-base": "^2.10.0",
52
+ "@opentelemetry/sdk-trace-node": "^2.10.0",
53
53
  "@opentelemetry/semantic-conventions": "^1.43.0",
54
54
  "@types/node": "^22.20.1",
55
- "ai": "^6.0.230",
55
+ "ai": "^6.0.235",
56
56
  "eslint": "^9.39.5",
57
- "openai": "^6.48.0",
57
+ "openai": "^6.49.0",
58
58
  "typescript": "5.9.3",
59
59
  "@repo/eslint-config": "0.0.0",
60
60
  "@repo/typescript-config": "0.0.0"
@@ -139,10 +139,10 @@
139
139
  "@opentelemetry/api": "^1.9.1",
140
140
  "https-proxy-agent": "^7.0.6",
141
141
  "proxy-from-env": "^2.1.0",
142
- "@introspection-sdk/http": "0.13.0",
143
- "@introspection-sdk/types": "0.13.0",
144
- "@introspection-sdk/introspection-proxy": "0.13.0",
145
- "@introspection-sdk/introspection-pi": "0.13.0"
142
+ "@introspection-sdk/http": "0.14.0",
143
+ "@introspection-sdk/introspection-pi": "0.14.0",
144
+ "@introspection-sdk/introspection-proxy": "0.14.0",
145
+ "@introspection-sdk/types": "0.14.0"
146
146
  },
147
147
  "scripts": {
148
148
  "lint": "eslint . --max-warnings 0",
package/src/client.ts CHANGED
@@ -28,6 +28,7 @@ import {
28
28
  type ExperimentsApi,
29
29
  } from "./resources/experiments.js";
30
30
  import { attachRecipes, type RecipesApi } from "./resources/recipes.js";
31
+ import { DEV_TARGET_HEADER, resolveDevTarget } from "./dev-target.js";
31
32
 
32
33
  /**
33
34
  * Introspection REST client.
@@ -77,7 +78,6 @@ export class IntrospectionClient {
77
78
  constructor(options: IntrospectionClientOptions = {}) {
78
79
  const token = options.token || process.env.INTROSPECTION_TOKEN || "";
79
80
  const advanced = options.advanced || {};
80
- this.advancedOptions = advanced;
81
81
  const baseApiUrl =
82
82
  advanced.baseApiUrl ||
83
83
  process.env.INTROSPECTION_BASE_API_URL ||
@@ -89,13 +89,24 @@ export class IntrospectionClient {
89
89
  );
90
90
  }
91
91
 
92
+ // INTROSPECTION_DEV_TARGET rides every request as a header so it reaches
93
+ // the paths a runner cannot: a bare `POST /v1/tasks` with a dev API key
94
+ // mints its JWT from the key row and has no per-request claim to carry.
95
+ // Merged first, so an explicit `additionalHeaders` entry still wins, and
96
+ // stored on advancedOptions so the Runner's own DP client inherits it.
97
+ const devTarget = resolveDevTarget();
98
+ const additionalHeaders = devTarget
99
+ ? { [DEV_TARGET_HEADER]: devTarget, ...advanced.additionalHeaders }
100
+ : advanced.additionalHeaders;
101
+ this.advancedOptions = { ...advanced, additionalHeaders };
102
+
92
103
  // CP HTTP client — talks to the customer-facing API with the customer
93
104
  // API key. Runners get their own HttpClient instances pointed at the
94
105
  // `deployment.endpoint` returned by `/v1/runtimes/{id}/run`.
95
106
  this.cpHttp = new HttpClient({
96
107
  apiUrl: baseApiUrl,
97
108
  token,
98
- additionalHeaders: advanced.additionalHeaders,
109
+ additionalHeaders: this.advancedOptions.additionalHeaders,
99
110
  fetch: advanced.fetch,
100
111
  });
101
112
 
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Development-target resolution — which `introspection dev` server this
3
+ * process's tasks should reach.
4
+ *
5
+ * Two developers can run `introspection dev` against one shared Runtime. A
6
+ * task created by a shared application credential carries no developer, so the
7
+ * platform cannot tell their machines apart; the caller names one instead.
8
+ * `introspection dev` prints the value to set:
9
+ *
10
+ * ```
11
+ * serving as: roland
12
+ * for your app: INTROSPECTION_DEV_TARGET=roland
13
+ * ```
14
+ *
15
+ * Carried as a header rather than on the runner's `caller` payload: `caller`
16
+ * is descriptive metadata the platform never acts on, and a target is a
17
+ * per-request selector the platform does act on. Keeping them apart is what
18
+ * lets `caller` stay a free-form bag, and it is the only transport that
19
+ * reaches a bare `POST /v1/tasks` with a dev API key, whose JWT is minted from
20
+ * the key row with no per-request input path.
21
+ *
22
+ * Deliberately env-only, with no `os.userInfo()` fallback. Defaulting to the
23
+ * local username would be zero-config on a laptop and wrong everywhere else: a
24
+ * process running in a shared development deployment under an account like
25
+ * `node` would silently name a machine nobody is serving and fail closed,
26
+ * where today it reaches the one connected dev server. The CLI defaults to the
27
+ * username because it is naming *itself* and always runs on the developer's
28
+ * machine; this names *someone else's* machine and can run anywhere.
29
+ *
30
+ * Inert outside development: the Data Plane consults a target only on the
31
+ * development pin path, so a stray value in staging or production is ignored.
32
+ */
33
+
34
+ /** Header carrying the target on requests that have no runner to ride. */
35
+ export const DEV_TARGET_HEADER = "x-introspection-dev-target";
36
+
37
+ /** The env var `introspection dev` prints and both the CLI and SDK read. */
38
+ export const DEV_TARGET_ENV = "INTROSPECTION_DEV_TARGET";
39
+
40
+ /**
41
+ * Percent-encode to RFC 3986, so the three SDKs put identical bytes on the
42
+ * wire for the same target.
43
+ *
44
+ * `encodeURIComponent` leaves `!'()*` alone where Python's `quote(safe="")`
45
+ * and the Rust client encode them. The Data Plane decodes before it
46
+ * normalizes, so either form routes — but a header that differs by which
47
+ * client sent it is a debugging trap for no benefit.
48
+ */
49
+ function encodeTarget(value: string): string {
50
+ return encodeURIComponent(value).replace(
51
+ /[!'()*]/g,
52
+ (c) => `%${c.charCodeAt(0).toString(16).toUpperCase()}`,
53
+ );
54
+ }
55
+
56
+ /**
57
+ * The development target for this process, or `undefined` when unset.
58
+ *
59
+ * Percent-encoded, because the value becomes an HTTP header and a header is
60
+ * bytes: a login name like `andré` is not transmissible as-is, and a runtime
61
+ * that lets it through sends latin-1 bytes the server would read back as a
62
+ * different string. Encoding here is lossless and costs nothing for the
63
+ * ordinary ASCII name, which encodes to itself.
64
+ *
65
+ * Safe to send encoded because the Data Plane decodes before it normalizes,
66
+ * so `andré` and `andr%C3%A9` land on the same target as the `--as andré`
67
+ * the CLI advertises over protobuf, where no encoding is needed.
68
+ *
69
+ * Read through `globalThis.process` so the module stays importable from
70
+ * non-Node runtimes that share this package's build.
71
+ */
72
+ export function resolveDevTarget(): string | undefined {
73
+ const env = (
74
+ globalThis as { process?: { env?: Record<string, string | undefined> } }
75
+ ).process?.env;
76
+ const raw = env?.[DEV_TARGET_ENV];
77
+ const trimmed = raw?.trim();
78
+ return trimmed ? encodeTarget(trimmed) : undefined;
79
+ }