@ory/argus 0.11.0 → 0.12.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/cli.js CHANGED
@@ -47,10 +47,11 @@ exports.interactiveConfigPrompt = interactiveConfigPrompt;
47
47
  exports.runAgentCommand = runAgentCommand;
48
48
  const fs = __importStar(require("node:fs"));
49
49
  const readline = __importStar(require("node:readline"));
50
- const client_1 = require("@ory/client");
51
50
  const config_js_1 = require("./config.js");
52
51
  const agent_auth_js_1 = require("./agent-auth.js");
53
52
  const tracer_js_1 = require("./tracer.js");
53
+ const cli_invocation_js_1 = require("./cli-invocation.js");
54
+ const client_js_1 = require("./client.js");
54
55
  /**
55
56
  * Shared `configure` command implementation for all plugin CLIs.
56
57
  *
@@ -67,14 +68,27 @@ const tracer_js_1 = require("./tracer.js");
67
68
  */
68
69
  function runConfigureCommand(binName, args) {
69
70
  let projectUrl;
71
+ let projectId;
70
72
  let apiKey;
71
73
  let oauth2ClientId;
72
74
  let auditOnly = false;
75
+ // `undefined` = not specified (leave the persisted value alone);
76
+ // true/false = explicit enable/disable of the interactive user login.
77
+ let userLogin;
78
+ // `undefined` = not specified; a string sets it; empty string ("") clears it
79
+ // (via --no-user-subject-namespace) to fall back to direct SubjectID.
80
+ let userSubjectNamespace;
73
81
  for (let i = 0; i < args.length; i++) {
74
82
  switch (args[i]) {
75
83
  case "--project-url":
84
+ // `--sdk-url` is the name the Ory Console "Get Started" uses; accept it
85
+ // as an alias so the value copied from there works verbatim.
86
+ case "--sdk-url":
76
87
  projectUrl = args[++i];
77
88
  break;
89
+ case "--project-id":
90
+ projectId = args[++i];
91
+ break;
78
92
  case "--api-key":
79
93
  apiKey = args[++i];
80
94
  break;
@@ -84,9 +98,27 @@ function runConfigureCommand(binName, args) {
84
98
  case "--audit-only":
85
99
  auditOnly = true;
86
100
  break;
101
+ case "--user-login":
102
+ userLogin = true;
103
+ break;
104
+ case "--no-user-login":
105
+ userLogin = false;
106
+ break;
107
+ case "--user-subject-namespace":
108
+ userSubjectNamespace = args[++i];
109
+ break;
110
+ case "--no-user-subject-namespace":
111
+ userSubjectNamespace = "";
112
+ break;
87
113
  }
88
114
  }
89
- if (!projectUrl && !apiKey && !oauth2ClientId && !auditOnly) {
115
+ if (!projectUrl &&
116
+ !projectId &&
117
+ !apiKey &&
118
+ !oauth2ClientId &&
119
+ !auditOnly &&
120
+ userLogin === undefined &&
121
+ userSubjectNamespace === undefined) {
90
122
  const resolved = (0, config_js_1.resolveConfig)();
91
123
  const configPath = (0, config_js_1.getConfigPath)();
92
124
  console.log("Ory Plugin Configuration");
@@ -94,35 +126,54 @@ function runConfigureCommand(binName, args) {
94
126
  console.log("");
95
127
  console.log(`Config file: ${configPath}`);
96
128
  console.log(`Project URL: ${resolved.projectUrl ?? "(not set)"} [${resolved.projectUrlSource}]`);
129
+ console.log(`Project ID: ${resolved.projectId ?? "(not set)"} [${resolved.projectIdSource}]`);
97
130
  console.log(`API Key: ${resolved.apiKey ? "(set)" : "(not set)"} [${resolved.apiKeySource}]`);
98
131
  console.log(`OAuth2 Client ID: ${resolved.oauth2ClientId ?? "(not set)"} [${resolved.oauth2ClientIdSource}]`);
99
132
  console.log(`Audit Only: ${resolved.auditOnly ? "yes" : "no"}`);
133
+ console.log(`User Login: ${resolved.userLogin ? "on" : "off"} [${resolved.userLoginSource}]`);
134
+ console.log(`User subject ns: ${resolved.userSubjectNamespace ?? "(direct subject id)"} [${resolved.userSubjectNamespaceSource}]`);
100
135
  console.log("");
101
136
  console.log("To configure:");
102
- console.log(` npx ${binName} configure --project-url <URL> --oauth2-client-id <CLIENT_ID> [--api-key <KEY>]`);
137
+ console.log(` ${(0, cli_invocation_js_1.oryNpx)(binName)} configure --project-url <URL> --oauth2-client-id <CLIENT_ID> [--api-key <KEY>]`);
138
+ console.log("");
139
+ console.log("To enable the interactive user login (PKCE browser flow at session start):");
140
+ console.log(` npx ${binName} configure --user-login (disable with --no-user-login)`);
141
+ console.log("");
142
+ console.log("To address the user as a SubjectSet in permission checks (must match your tuples):");
143
+ console.log(` ${(0, cli_invocation_js_1.oryNpx)(binName)} configure --user-subject-namespace User (clear with --no-user-subject-namespace)`);
103
144
  console.log("");
104
145
  console.log("To enable audit logging only (no auth or permission checks):");
105
- console.log(` npx ${binName} configure --audit-only`);
146
+ console.log(` ${(0, cli_invocation_js_1.oryNpx)(binName)} configure --audit-only`);
106
147
  console.log("");
107
148
  console.log("Or set environment variables:");
108
149
  console.log(" export ORY_PROJECT_URL=https://your-project.projects.oryapis.com");
150
+ console.log(" # ORY_SDK_URL (the Ory Console 'Get Started' name) is accepted as an alias.");
151
+ console.log(" # ORY_PROJECT_ID=<project uuid> is stored for admin operations (not an SDK URL).");
109
152
  console.log(" export ORY_OAUTH2_CLIENT_ID=<public OAuth2 client id>");
110
153
  console.log(" export ORY_AGENT_API_KEY=ory_pat_...");
154
+ console.log(" export ORY_USER_LOGIN=true");
111
155
  return;
112
156
  }
113
157
  if (auditOnly) {
114
- // Audit-only mode: clear projectUrl/apiKey, set auditOnly flag
115
- (0, config_js_1.saveConfig)({ auditOnly: true });
158
+ // Audit-only mode: set the kill switch. Persist an explicit user-login
159
+ // choice too if one was passed, so it takes effect once audit-only is
160
+ // later turned off; audit-only itself disables login regardless.
161
+ (0, config_js_1.saveConfig)({ auditOnly: true, ...(userLogin !== undefined ? { userLogin } : {}) });
116
162
  const configPath = (0, config_js_1.getConfigPath)();
117
163
  console.log(`Configuration saved to ${configPath}`);
118
164
  console.log(" Mode: audit-only (logging enabled, auth and permission checks disabled)");
165
+ if (userLogin !== undefined) {
166
+ console.log(` User login: ${userLogin ? "on" : "off"} (takes effect when audit-only is disabled)`);
167
+ }
119
168
  console.log("");
120
169
  console.log("This configuration is shared across all Ory agent plugins.");
121
170
  return;
122
171
  }
123
- // When --project-url is provided we need a usable OAuth2 client id for
124
- // the user PKCE flow — block the configure with a clear error if none
125
- // is reachable from the flag, env, or already-persisted config.
172
+ // When --project-url / --sdk-url is provided we need a usable OAuth2 client
173
+ // id for the user PKCE flow — block the configure with a clear error if none
174
+ // is reachable from the flag, env, or already-persisted config. A bare
175
+ // --project-id sets an admin identifier only (not an SDK URL), so it doesn't
176
+ // trigger this gate on its own.
126
177
  if (projectUrl) {
127
178
  const persisted = (0, config_js_1.loadConfig)().oauth2ClientId;
128
179
  const envClientId = process.env.ORY_OAUTH2_CLIENT_ID;
@@ -152,31 +203,67 @@ function runConfigureCommand(binName, args) {
152
203
  " --redirect-uri http://127.0.0.1:47826/callback\n" +
153
204
  "\n" +
154
205
  "If you only want audit logging (no auth or permission checks), use:\n" +
155
- ` npx ${binName} configure --audit-only`);
206
+ ` ${(0, cli_invocation_js_1.oryNpx)(binName)} configure --audit-only`);
156
207
  process.exit(1);
157
208
  }
158
209
  }
210
+ // Enabling user login needs a project URL and a public OAuth2 client id
211
+ // to complete the PKCE flow. Warn (don't block) if either is missing —
212
+ // the operator may supply them separately or via env before running.
213
+ if (userLogin === true) {
214
+ // resolveConfig() already folds in the ORY_SDK_URL alias and the config
215
+ // file; OR in the URL being set on this same invocation.
216
+ const nextProjectUrl = projectUrl ?? (0, config_js_1.resolveConfig)().projectUrl;
217
+ const nextClientId = oauth2ClientId ?? process.env.ORY_OAUTH2_CLIENT_ID ?? (0, config_js_1.loadConfig)().oauth2ClientId;
218
+ if (!nextProjectUrl || !nextClientId) {
219
+ const missing = [
220
+ !nextProjectUrl ? "a project URL (--project-url / --sdk-url / ORY_PROJECT_URL)" : null,
221
+ !nextClientId ? "an OAuth2 client id (--oauth2-client-id / ORY_OAUTH2_CLIENT_ID)" : null,
222
+ ].filter(Boolean);
223
+ console.warn(`Warning: user login is enabled but still missing ${missing.join(" and ")}.\n` +
224
+ "The PKCE browser flow can't complete until both are configured.");
225
+ }
226
+ }
159
227
  const update = {};
160
228
  if (projectUrl)
161
229
  update.projectUrl = projectUrl;
230
+ if (projectId)
231
+ update.projectId = projectId;
162
232
  if (apiKey)
163
233
  update.apiKey = apiKey;
164
234
  if (oauth2ClientId)
165
235
  update.oauth2ClientId = oauth2ClientId;
166
- // Clear auditOnly when configuring with a project URL
167
- update.auditOnly = false;
236
+ if (userLogin !== undefined)
237
+ update.userLogin = userLogin;
238
+ // A non-empty namespace sets the SubjectSet namespace; the empty string
239
+ // (from --no-user-subject-namespace) clears it (null ⇒ delete the key).
240
+ if (userSubjectNamespace !== undefined) {
241
+ update.userSubjectNamespace = userSubjectNamespace === "" ? null : userSubjectNamespace;
242
+ }
243
+ // Configuring an actual connection (a slug-based URL, api key, or client id)
244
+ // implies leaving audit-only mode. A bare project id is only an admin
245
+ // identifier — it doesn't connect anything on its own — so it doesn't flip
246
+ // the flag; nor does a standalone user-login toggle.
247
+ if (projectUrl || apiKey || oauth2ClientId)
248
+ update.auditOnly = false;
168
249
  (0, config_js_1.saveConfig)(update);
169
250
  const configPath = (0, config_js_1.getConfigPath)();
170
251
  console.log(`Configuration saved to ${configPath}`);
171
252
  if (projectUrl)
172
253
  console.log(` Project URL: ${projectUrl}`);
254
+ if (projectId)
255
+ console.log(` Project ID: ${projectId}`);
173
256
  if (apiKey)
174
257
  console.log(` API Key: (set)`);
175
258
  if (oauth2ClientId)
176
259
  console.log(` OAuth2 Client ID: ${oauth2ClientId}`);
260
+ if (userLogin !== undefined)
261
+ console.log(` User Login: ${userLogin ? "on" : "off"}`);
262
+ if (userSubjectNamespace !== undefined)
263
+ console.log(` User subject namespace: ${userSubjectNamespace === "" ? "(cleared — direct subject id)" : userSubjectNamespace}`);
177
264
  console.log("");
178
265
  console.log("This configuration is shared across all Ory agent plugins.");
179
- console.log("Environment variables (ORY_PROJECT_URL, ORY_AGENT_API_KEY, ORY_OAUTH2_CLIENT_ID) take precedence when set.");
266
+ console.log("Environment variables (ORY_PROJECT_URL, ORY_AGENT_API_KEY, ORY_OAUTH2_CLIENT_ID, ORY_USER_LOGIN) take precedence when set.");
180
267
  }
181
268
  /**
182
269
  * Print the "Configuration:" block showing Ory project URL and API key status.
@@ -189,10 +276,13 @@ function printOryConfig() {
189
276
  console.log(` Config file: ${configPath}`);
190
277
  console.log(` Mode: ${resolved.auditOnly ? "audit-only" : "full"}`);
191
278
  console.log(` Project URL: ${resolved.projectUrl ?? "NOT SET"} [source: ${resolved.projectUrlSource}]`);
279
+ console.log(` Project ID: ${resolved.projectId ?? "NOT SET"} [source: ${resolved.projectIdSource}]`);
192
280
  console.log(` API Key: ${resolved.apiKey ? "(set)" : "NOT SET"} [source: ${resolved.apiKeySource}]`);
193
281
  console.log(` OAuth2 Client: ${resolved.oauth2ClientId ?? "NOT SET"} [source: ${resolved.oauth2ClientIdSource}]`);
194
282
  console.log(` Permission mode: ${resolved.permissionMode} [source: ${resolved.permissionModeSource}]`);
283
+ console.log(` User login: ${resolved.userLogin ? "on" : "off"} [source: ${resolved.userLoginSource}]`);
195
284
  console.log(` Namespace: ${namespace}`);
285
+ console.log(` User subject ns: ${resolved.userSubjectNamespace ?? "(direct subject id)"} [source: ${resolved.userSubjectNamespaceSource}]`);
196
286
  }
197
287
  /**
198
288
  * Print the "Environment:" block showing Ory-related environment variables.
@@ -201,6 +291,9 @@ function printEnvironment() {
201
291
  console.log("");
202
292
  console.log("Environment:");
203
293
  const vars = [
294
+ ["ORY_PROJECT_URL", process.env.ORY_PROJECT_URL, false],
295
+ ["ORY_SDK_URL", process.env.ORY_SDK_URL, false],
296
+ ["ORY_PROJECT_ID", process.env.ORY_PROJECT_ID, false],
204
297
  ["ORY_USER_LOGIN", process.env.ORY_USER_LOGIN, false],
205
298
  [
206
299
  "ORY_AGENT_API_KEY",
@@ -238,10 +331,17 @@ function printEnvironment() {
238
331
  }
239
332
  }
240
333
  /**
241
- * Print the last 5 debug log entries if ORY_AGENT_LOG_FILE is set and exists.
334
+ * Print the last 5 debug log entries. When `harness` is given the path is
335
+ * resolved the same way the plugin does at runtime — the default per-harness
336
+ * data-dir location when `ORY_AGENT_LOG_FILE` is unset — so `status` finds the
337
+ * log without the reader hand-setting env vars. The debug log only exists when
338
+ * a session ran with `ORY_AGENT_DEBUG=true`; when it doesn't, this prints a
339
+ * one-line pointer on how to turn it on rather than staying silent.
242
340
  */
243
- function printLogTail() {
244
- const logFile = process.env.ORY_AGENT_LOG_FILE;
341
+ function printLogTail(harness) {
342
+ const logFile = harness
343
+ ? (0, client_js_1.resolveDebugLogPath)(harness)
344
+ : process.env.ORY_AGENT_LOG_FILE;
245
345
  if (logFile && fs.existsSync(logFile)) {
246
346
  const lines = fs.readFileSync(logFile, "utf-8").trim().split("\n");
247
347
  console.log("");
@@ -257,6 +357,12 @@ function printLogTail() {
257
357
  }
258
358
  }
259
359
  }
360
+ else if (harness) {
361
+ console.log("");
362
+ console.log(logFile
363
+ ? `Debug log: none yet — run a session with ORY_AGENT_DEBUG=true to write ${logFile}`
364
+ : "Debug log: disabled (ORY_AGENT_LOG_FILE set empty)");
365
+ }
260
366
  }
261
367
  /**
262
368
  * Print the "Configure your Ory credentials" help text.
@@ -266,7 +372,7 @@ function printEnvHelp(binName) {
266
372
  console.log("Configure your Ory credentials (one of these methods):");
267
373
  console.log("");
268
374
  console.log(" Option 1 — Save to config file (persists across sessions):");
269
- console.log(` npx ${binName} configure --project-url https://your-project.projects.oryapis.com \\`);
375
+ console.log(` ${(0, cli_invocation_js_1.oryNpx)(binName)} configure --project-url https://your-project.projects.oryapis.com \\`);
270
376
  console.log(" --oauth2-client-id <public OAuth2 client id> \\");
271
377
  console.log(" --api-key ory_pat_...");
272
378
  console.log("");
@@ -278,10 +384,17 @@ function printEnvHelp(binName) {
278
384
  console.log("If neither is set when a session starts, the agent will prompt for configuration.");
279
385
  }
280
386
  /**
281
- * Print the last 5 trace entries if ORY_AGENT_TRACE_FILE is set and exists.
387
+ * Print the last 5 trace spans. When `harness` is given the path is resolved
388
+ * the same way the plugin does at runtime — the default per-harness data-dir
389
+ * location when `ORY_AGENT_TRACE_FILE` is unset — so `status` shows recent
390
+ * activity out of the box (traces are written on every recorded span). When no
391
+ * spans have been recorded yet, prints a one-line pointer at the trace file so
392
+ * the reader knows where to look (and how to watch it live).
282
393
  */
283
- function printTraceTail() {
284
- const traceFile = process.env.ORY_AGENT_TRACE_FILE;
394
+ function printTraceTail(harness) {
395
+ const traceFile = harness
396
+ ? (0, client_js_1.resolveTraceFilePath)(harness)
397
+ : process.env.ORY_AGENT_TRACE_FILE;
285
398
  if (traceFile && fs.existsSync(traceFile)) {
286
399
  const lines = fs.readFileSync(traceFile, "utf-8").trim().split("\n");
287
400
  console.log("");
@@ -297,22 +410,32 @@ function printTraceTail() {
297
410
  }
298
411
  }
299
412
  }
413
+ else if (harness) {
414
+ console.log("");
415
+ console.log(traceFile
416
+ ? `Trace file: none yet — spans land in ${traceFile} once a session runs a tool`
417
+ : "Trace file: disabled (ORY_AGENT_TRACE_FILE set empty)");
418
+ }
300
419
  }
301
420
  /**
302
421
  * Run the live trace watcher. Tails the NDJSON trace file and prints
303
422
  * formatted spans to stdout as they arrive. Blocks until interrupted.
304
423
  */
305
- function runWatchCommand(args) {
306
- let traceFile = args[0];
307
- if (!traceFile) {
308
- traceFile = process.env.ORY_AGENT_TRACE_FILE ?? "";
309
- }
424
+ function runWatchCommand(harness, args) {
425
+ // Precedence: explicit arg → resolved default (honors ORY_AGENT_TRACE_FILE,
426
+ // falling back to the per-harness data-dir path). The resolver returns
427
+ // undefined only when tracing is explicitly disabled (ORY_AGENT_TRACE_FILE
428
+ // set empty), so that's the one case that dead-ends here.
429
+ const traceFile = args[0] || (0, client_js_1.resolveTraceFilePath)(harness);
310
430
  if (!traceFile) {
311
- console.error("Usage: watch <trace-file>\n" +
312
- " Or set ORY_AGENT_TRACE_FILE environment variable.\n");
431
+ console.error("Trace file is disabled (ORY_AGENT_TRACE_FILE is set empty).\n" +
432
+ "Unset it, or pass a path: watch <trace-file>\n");
313
433
  process.exit(1);
314
434
  }
315
435
  console.log(`Watching traces: ${traceFile}`);
436
+ if (!fs.existsSync(traceFile)) {
437
+ console.log("(file doesn't exist yet — waiting for the first span…)");
438
+ }
316
439
  console.log("Press Ctrl+C to stop.\n");
317
440
  const stop = (0, tracer_js_1.watchTraceFile)(traceFile, (span) => {
318
441
  console.log((0, tracer_js_1.formatSpan)(span));
@@ -382,7 +505,7 @@ async function promptForProjectUrl(binName) {
382
505
  "--------------------------------------------",
383
506
  "",
384
507
  "No Ory project URL is configured for this session.",
385
- `Enter your Ory project URL to continue, or press Enter to skip and run \`npx ${binName} configure\` later.`,
508
+ `Enter your Ory project URL to continue, or press Enter to skip and run \`${(0, cli_invocation_js_1.oryNpx)(binName)} configure\` later.`,
386
509
  "",
387
510
  "Example: https://your-project.projects.oryapis.com",
388
511
  "",
@@ -430,10 +553,10 @@ async function interactiveConfigPrompt(binName) {
430
553
  "Run one of the following commands in another terminal:",
431
554
  "",
432
555
  " Connect to Ory (enables auth & permission checks):",
433
- ` npx ${binName} configure --project-url <URL> --oauth2-client-id <CLIENT_ID> [--api-key <KEY>]`,
556
+ ` ${(0, cli_invocation_js_1.oryNpx)(binName)} configure --project-url <URL> --oauth2-client-id <CLIENT_ID> [--api-key <KEY>]`,
434
557
  "",
435
558
  " Or, enable audit logging only (no auth or permission checks):",
436
- ` npx ${binName} configure --audit-only`,
559
+ ` ${(0, cli_invocation_js_1.oryNpx)(binName)} configure --audit-only`,
437
560
  "",
438
561
  `Config is saved to ${configPath}`,
439
562
  "and shared across all agent plugins.",
@@ -538,31 +661,16 @@ async function runAgentUnregister() {
538
661
  console.log("No registered agent client to unregister. Nothing to do.");
539
662
  return 0;
540
663
  }
541
- if (persisted.registrationClientUri && persisted.registrationAccessToken) {
542
- const oidc = new client_1.OidcApi(new client_1.Configuration({
543
- basePath: persisted.projectUrl,
544
- accessToken: persisted.registrationAccessToken,
545
- }));
546
- try {
547
- await oidc.deleteOidcDynamicClient({ id: persisted.clientId });
548
- }
549
- catch (err) {
550
- const status = err?.response?.status;
551
- if (status === 404) {
552
- // Already gone server-side; nothing to warn about.
553
- }
554
- else if (typeof status === "number") {
555
- console.warn(`Warning: server-side DELETE returned HTTP ${status}. Local state will be cleared anyway.`);
556
- }
557
- else {
558
- const msg = err instanceof Error ? err.message : String(err);
559
- console.warn(`Warning: server-side DELETE failed (${msg}). Local state will be cleared anyway.`);
560
- }
561
- }
562
- }
563
- else {
664
+ const outcome = await (0, agent_auth_js_1.revokeAgentDynamicClient)(persisted);
665
+ if (outcome.status === "skipped") {
564
666
  console.warn("Warning: no registration_access_token was persisted, so we cannot DELETE the server-side client. Clearing local state only.");
565
667
  }
668
+ else if (outcome.status === "failed") {
669
+ const detail = typeof outcome.httpStatus === "number"
670
+ ? `returned HTTP ${outcome.httpStatus}`
671
+ : `failed (${outcome.message})`;
672
+ console.warn(`Warning: server-side DELETE ${detail}. Local state will be cleared anyway.`);
673
+ }
566
674
  (0, agent_auth_js_1.clearAgentDynamicCredentials)();
567
675
  console.log(`Unregistered agent client ${persisted.clientId}.`);
568
676
  return 0;
package/dist/client.d.ts CHANGED
@@ -13,6 +13,13 @@ export interface OryAgentConfig {
13
13
  logFile?: string;
14
14
  /** Optional NDJSON trace file path for structured span output */
15
15
  traceFile?: string;
16
+ /**
17
+ * Permission-check subject namespace for the human user. When set, the
18
+ * user is addressed as a SubjectSet `<namespace>:<subject>` (matching how
19
+ * the tuples were written in Keto) rather than a direct SubjectID. Read by
20
+ * {@link resolveUserSubject}; `ORY_USER_SUBJECT_NAMESPACE` overrides it.
21
+ */
22
+ userSubjectNamespace?: string;
16
23
  /**
17
24
  * Session cache TTL in milliseconds.
18
25
  * Set to 0 to disable caching. Default: 60_000 (1 minute).
@@ -58,6 +65,13 @@ export declare class OryAgentClient {
58
65
  get userPrincipal(): PrincipalIdentity;
59
66
  /** Snapshot of the current agent principal. */
60
67
  get agentPrincipal(): PrincipalIdentity;
68
+ /**
69
+ * Configured user-subject namespace (from config, resolved at construction).
70
+ * `resolveUserSubject` uses this as the SubjectSet namespace when the
71
+ * `ORY_USER_SUBJECT_NAMESPACE` env var isn't set. Undefined ⇒ direct
72
+ * SubjectID resolution.
73
+ */
74
+ get userSubjectNamespace(): string | undefined;
61
75
  /**
62
76
  * Set or update the human user principal. The user is the subject of
63
77
  * permission checks but does not authenticate outgoing API calls.
@@ -151,6 +165,19 @@ export declare class OryAgentClient {
151
165
  */
152
166
  static fromEnv(harness: string): OryAgentClient;
153
167
  }
168
+ /** Default debug-log path under the shared per-harness data dir. */
169
+ export declare const DEFAULT_DEBUG_LOG_FILENAME = "ory-agent-debug.log";
170
+ /** Default trace (NDJSON) path under the shared per-harness data dir. */
171
+ export declare const DEFAULT_TRACE_FILENAME = "ory-agent-trace.ndjson";
172
+ /**
173
+ * Debug log path. Only written when `ORY_AGENT_DEBUG=true` (the logger gates
174
+ * on that); defaulting the path just means an enabled debug session lands in a
175
+ * file automatically — important for subprocess-hook harnesses whose stderr
176
+ * the harness may swallow.
177
+ */
178
+ export declare function resolveDebugLogPath(harness: string): string | undefined;
179
+ /** Trace (NDJSON) path. Written on every recorded span when set. */
180
+ export declare function resolveTraceFilePath(harness: string): string | undefined;
154
181
  /**
155
182
  * Pull the Ory backend request ID from a response headers bag (axios returns
156
183
  * lowercase header names). Returns undefined when not present.
package/dist/client.js CHANGED
@@ -1,8 +1,44 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
2
35
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.OryAgentClient = void 0;
36
+ exports.DEFAULT_TRACE_FILENAME = exports.DEFAULT_DEBUG_LOG_FILENAME = exports.OryAgentClient = void 0;
37
+ exports.resolveDebugLogPath = resolveDebugLogPath;
38
+ exports.resolveTraceFilePath = resolveTraceFilePath;
4
39
  exports.extractOryRequestId = extractOryRequestId;
5
40
  const client_1 = require("@ory/client");
41
+ const path = __importStar(require("node:path"));
6
42
  const logger_js_1 = require("./logger.js");
7
43
  const tracer_js_1 = require("./tracer.js");
8
44
  const config_js_1 = require("./config.js");
@@ -75,6 +111,15 @@ class OryAgentClient {
75
111
  get agentPrincipal() {
76
112
  return { ...this._agentPrincipal };
77
113
  }
114
+ /**
115
+ * Configured user-subject namespace (from config, resolved at construction).
116
+ * `resolveUserSubject` uses this as the SubjectSet namespace when the
117
+ * `ORY_USER_SUBJECT_NAMESPACE` env var isn't set. Undefined ⇒ direct
118
+ * SubjectID resolution.
119
+ */
120
+ get userSubjectNamespace() {
121
+ return this.config.userSubjectNamespace;
122
+ }
78
123
  /**
79
124
  * Set or update the human user principal. The user is the subject of
80
125
  * permission checks but does not authenticate outgoing API calls.
@@ -600,6 +645,8 @@ class OryAgentClient {
600
645
  static fromEnv(harness) {
601
646
  const resolved = (0, config_js_1.resolveConfig)();
602
647
  const projectUrl = resolved.projectUrl;
648
+ const logFile = resolveDebugLogPath(harness);
649
+ const traceFile = resolveTraceFilePath(harness);
603
650
  if (!projectUrl) {
604
651
  // Use a placeholder URL so the client can be constructed.
605
652
  // API calls will fail with network_error which is handled as fail-open.
@@ -607,8 +654,9 @@ class OryAgentClient {
607
654
  projectUrl: "http://localhost:0",
608
655
  apiKey: resolved.apiKey,
609
656
  harness,
610
- logFile: process.env.ORY_AGENT_LOG_FILE,
611
- traceFile: process.env.ORY_AGENT_TRACE_FILE,
657
+ logFile,
658
+ traceFile,
659
+ userSubjectNamespace: resolved.userSubjectNamespace,
612
660
  sessionCacheTtlMs: process.env.ORY_SESSION_CACHE_TTL_MS
613
661
  ? parseInt(process.env.ORY_SESSION_CACHE_TTL_MS, 10)
614
662
  : undefined,
@@ -625,8 +673,9 @@ class OryAgentClient {
625
673
  projectUrl,
626
674
  apiKey: resolved.apiKey,
627
675
  harness,
628
- logFile: process.env.ORY_AGENT_LOG_FILE,
629
- traceFile: process.env.ORY_AGENT_TRACE_FILE,
676
+ logFile,
677
+ traceFile,
678
+ userSubjectNamespace: resolved.userSubjectNamespace,
630
679
  sessionCacheTtlMs: process.env.ORY_SESSION_CACHE_TTL_MS
631
680
  ? parseInt(process.env.ORY_SESSION_CACHE_TTL_MS, 10)
632
681
  : undefined,
@@ -640,6 +689,37 @@ class OryAgentClient {
640
689
  }
641
690
  }
642
691
  exports.OryAgentClient = OryAgentClient;
692
+ /** Default debug-log path under the shared per-harness data dir. */
693
+ exports.DEFAULT_DEBUG_LOG_FILENAME = "ory-agent-debug.log";
694
+ /** Default trace (NDJSON) path under the shared per-harness data dir. */
695
+ exports.DEFAULT_TRACE_FILENAME = "ory-agent-trace.ndjson";
696
+ /**
697
+ * Resolve a file path from an env var with a sensible default under the
698
+ * per-harness data dir. Semantics:
699
+ * - unset → the default path (so post-install runs are observable
700
+ * without hand-setting env vars),
701
+ * - set to a path → that path (operator / dev-launcher override),
702
+ * - set but empty → `undefined` (explicit opt-out, e.g. `ORY_AGENT_TRACE_FILE=`).
703
+ */
704
+ function resolveFilePath(envValue, defaultPath) {
705
+ if (envValue === undefined)
706
+ return defaultPath;
707
+ const trimmed = envValue.trim();
708
+ return trimmed.length > 0 ? trimmed : undefined;
709
+ }
710
+ /**
711
+ * Debug log path. Only written when `ORY_AGENT_DEBUG=true` (the logger gates
712
+ * on that); defaulting the path just means an enabled debug session lands in a
713
+ * file automatically — important for subprocess-hook harnesses whose stderr
714
+ * the harness may swallow.
715
+ */
716
+ function resolveDebugLogPath(harness) {
717
+ return resolveFilePath(process.env.ORY_AGENT_LOG_FILE, path.join((0, config_js_1.getHarnessDataDir)(harness), exports.DEFAULT_DEBUG_LOG_FILENAME));
718
+ }
719
+ /** Trace (NDJSON) path. Written on every recorded span when set. */
720
+ function resolveTraceFilePath(harness) {
721
+ return resolveFilePath(process.env.ORY_AGENT_TRACE_FILE, path.join((0, config_js_1.getHarnessDataDir)(harness), exports.DEFAULT_TRACE_FILENAME));
722
+ }
643
723
  function attachOtlpExporterFromEnv(client, harness) {
644
724
  const meta = client.tracer.processMetadata;
645
725
  const exporter = (0, otlp_js_1.otlpExporterFromEnv)({