@ory/argus 0.14.0 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +31 -46
- package/assets/commands/temporal-up.md +1 -1
- package/assets/skills/auth-setup/SKILL.md +1 -1
- package/assets/skills/local-dev/SKILL.md +17 -7
- package/assets/skills/ory-build-agent/SKILL.md +39 -91
- package/assets/skills/ory-e2b-sandbox/SKILL.md +18 -17
- package/assets/skills/ory-temporal-worker/SKILL.md +31 -33
- package/assets/skills/permissions-onboarding/SKILL.md +131 -104
- package/dist/adapters.d.ts +88 -32
- package/dist/adapters.js +443 -164
- package/dist/agent-auth.d.ts +226 -67
- package/dist/agent-auth.js +951 -205
- package/dist/auth-store.d.ts +37 -2
- package/dist/auth-store.js +37 -3
- package/dist/auth.d.ts +33 -4
- package/dist/auth.js +163 -20
- package/dist/bash-parser.d.ts +98 -0
- package/dist/bash-parser.js +396 -0
- package/dist/branding.d.ts +77 -16
- package/dist/branding.js +93 -23
- package/dist/build-info.json +4 -4
- package/dist/cli-invocation.d.ts +1 -1
- package/dist/cli-invocation.js +2 -1
- package/dist/cli.d.ts +20 -29
- package/dist/cli.js +271 -239
- package/dist/client.d.ts +175 -138
- package/dist/client.js +672 -391
- package/dist/config.d.ts +217 -54
- package/dist/config.js +461 -42
- package/dist/context.d.ts +10 -0
- package/dist/context.js +21 -0
- package/dist/contract-suite.d.ts +3 -5
- package/dist/contract-suite.js +75 -47
- package/dist/denial.d.ts +36 -3
- package/dist/denial.js +79 -10
- package/dist/event-reporter.d.ts +77 -0
- package/dist/event-reporter.js +776 -0
- package/dist/external-registrations-main.d.ts +10 -0
- package/dist/external-registrations-main.js +38 -0
- package/dist/external-registrations.d.ts +79 -0
- package/dist/external-registrations.js +188 -0
- package/dist/help-cli.d.ts +39 -0
- package/dist/help-cli.js +55 -0
- package/dist/hook-timeout.d.ts +64 -0
- package/dist/hook-timeout.js +88 -0
- package/dist/index.d.ts +28 -23
- package/dist/index.js +173 -58
- package/dist/lifecycle.d.ts +3 -3
- package/dist/lifecycle.js +38 -6
- package/dist/local/cli.js +11 -6
- package/dist/local/configs.d.ts +74 -18
- package/dist/local/configs.js +291 -84
- package/dist/local/health.js +7 -7
- package/dist/local/index.d.ts +2 -2
- package/dist/local/index.js +24 -10
- package/dist/local/manager.d.ts +20 -1
- package/dist/local/manager.js +159 -36
- package/dist/local/ports.d.ts +158 -0
- package/dist/local/ports.js +443 -0
- package/dist/local/seed.d.ts +13 -5
- package/dist/local/seed.js +62 -38
- package/dist/logger.d.ts +54 -25
- package/dist/logger.js +329 -63
- package/dist/mcp.d.ts +2 -2
- package/dist/mcp.js +10 -5
- package/dist/mirror-bootstrap.d.ts +48 -0
- package/dist/mirror-bootstrap.js +254 -0
- package/dist/opl.d.ts +289 -0
- package/dist/opl.js +446 -0
- package/dist/permission-mode.d.ts +87 -0
- package/dist/permission-mode.js +307 -0
- package/dist/permissions-cli.d.ts +13 -49
- package/dist/permissions-cli.js +154 -348
- package/dist/permissions.d.ts +148 -38
- package/dist/permissions.js +591 -45
- package/dist/post-install.d.ts +33 -0
- package/dist/post-install.js +127 -0
- package/dist/read-credential.d.ts +65 -0
- package/dist/read-credential.js +86 -0
- package/dist/registry/cli.js +5 -2
- package/dist/registry/config.d.ts +0 -17
- package/dist/registry/config.js +0 -23
- package/dist/registry/index.d.ts +1 -1
- package/dist/registry/index.js +2 -2
- package/dist/registry/manager.d.ts +4 -21
- package/dist/registry/manager.js +21 -37
- package/dist/runtime-credential.d.ts +140 -0
- package/dist/runtime-credential.js +572 -0
- package/dist/runtime.d.ts +413 -0
- package/dist/runtime.js +825 -0
- package/dist/setup.d.ts +23 -47
- package/dist/setup.js +59 -116
- package/dist/skills.js +0 -7
- package/dist/status-cli.d.ts +27 -11
- package/dist/status-cli.js +121 -115
- package/dist/status-data.d.ts +116 -17
- package/dist/status-data.js +121 -38
- package/dist/subject.d.ts +126 -20
- package/dist/subject.js +215 -30
- package/dist/testing.d.ts +74 -38
- package/dist/testing.js +185 -68
- package/dist/tool-catalog.d.ts +53 -11
- package/dist/tool-catalog.js +164 -13
- package/dist/tool-metadata.d.ts +7 -6
- package/dist/tool-metadata.js +6 -5
- package/dist/types.d.ts +11 -1
- package/dist/uninstall.d.ts +71 -34
- package/dist/uninstall.js +217 -85
- package/dist/user-login.d.ts +9 -10
- package/dist/user-login.js +56 -75
- package/dist/watch-cli.d.ts +6 -0
- package/dist/watch-cli.js +217 -0
- package/package.json +4 -27
- package/assets/commands/dashboard.md +0 -34
- package/dist/dashboard-cli.d.ts +0 -8
- package/dist/dashboard-cli.js +0 -70
- package/dist/dev.d.ts +0 -103
- package/dist/dev.js +0 -583
- package/dist/interactive-setup.d.ts +0 -286
- package/dist/interactive-setup.js +0 -1734
- package/dist/local/jaeger-main.d.ts +0 -13
- package/dist/local/jaeger-main.js +0 -85
- package/dist/local/jaeger.d.ts +0 -50
- package/dist/local/jaeger.js +0 -162
- package/dist/otel/exporter.d.ts +0 -17
- package/dist/otel/exporter.js +0 -12
- package/dist/otel/index.d.ts +0 -2
- package/dist/otel/index.js +0 -8
- package/dist/otel/otlp.d.ts +0 -103
- package/dist/otel/otlp.js +0 -385
- package/dist/project-api-key.d.ts +0 -69
- package/dist/project-api-key.js +0 -147
- package/dist/setup-actions.d.ts +0 -232
- package/dist/setup-actions.js +0 -507
- package/dist/tracer.d.ts +0 -190
- package/dist/tracer.js +0 -481
- package/dist/watch-sandbox.d.ts +0 -9
- package/dist/watch-sandbox.js +0 -81
- package/dist/web/api.d.ts +0 -33
- package/dist/web/api.js +0 -294
- package/dist/web/launch.d.ts +0 -11
- package/dist/web/launch.js +0 -96
- package/dist/web/server.d.ts +0 -20
- package/dist/web/server.js +0 -233
- package/dist/web/types.d.ts +0 -65
- package/dist/web/types.js +0 -2
- package/dist/webapp/assets/index-Wucl4SZs.css +0 -1
- package/dist/webapp/assets/index-m-GtEdq0.js +0 -49
- package/dist/webapp/favicon.ico +0 -0
- package/dist/webapp/index.html +0 -15
package/dist/config.js
CHANGED
|
@@ -33,19 +33,49 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.LOCAL_AGENT_SECURITY_URL = exports.DEFAULT_AGENT_SECURITY_URL = exports.DEFAULT_OAUTH2_CLIENT_ID = exports.SESSIONLESS_KEY = exports.UNKNOWN_HARNESS_KEY = exports.DELEGATION_NODE_HISTORY = void 0;
|
|
36
37
|
exports.getDataDir = getDataDir;
|
|
37
38
|
exports.getHarnessDataDir = getHarnessDataDir;
|
|
38
39
|
exports.getConfigPath = getConfigPath;
|
|
39
40
|
exports.loadConfig = loadConfig;
|
|
41
|
+
exports.listInstalledHarnesses = listInstalledHarnesses;
|
|
42
|
+
exports.registerInstalledHarness = registerInstalledHarness;
|
|
43
|
+
exports.unregisterInstalledHarness = unregisterInstalledHarness;
|
|
40
44
|
exports.saveConfig = saveConfig;
|
|
41
45
|
exports.mutateConfig = mutateConfig;
|
|
42
46
|
exports.looksLikeProjectId = looksLikeProjectId;
|
|
47
|
+
exports.isSecurityConnected = isSecurityConnected;
|
|
48
|
+
exports.describeSecurityGap = describeSecurityGap;
|
|
43
49
|
exports.resolveConfig = resolveConfig;
|
|
44
50
|
exports.configPromptMessage = configPromptMessage;
|
|
45
51
|
const fs = __importStar(require("node:fs"));
|
|
46
52
|
const os = __importStar(require("node:os"));
|
|
47
53
|
const path = __importStar(require("node:path"));
|
|
48
54
|
const cli_invocation_js_1 = require("./cli-invocation.js");
|
|
55
|
+
/**
|
|
56
|
+
* How many sessions' delegation node ids to keep per credential. Only the
|
|
57
|
+
* current session's is ever read; the rest are kept as a small audit tail and
|
|
58
|
+
* bounded so a long-lived install's config doesn't grow without limit.
|
|
59
|
+
*/
|
|
60
|
+
exports.DELEGATION_NODE_HISTORY = 10;
|
|
61
|
+
/**
|
|
62
|
+
* Key used when a credential record carries no harness of its own — only
|
|
63
|
+
* reachable by migrating a config written before credentials were keyed by
|
|
64
|
+
* harness, where the `harness` field had never been persisted. Such a record
|
|
65
|
+
* is never re-used (no harness matches it), but it stays addressable so
|
|
66
|
+
* uninstall can still revoke the server-side client rather than orphaning it.
|
|
67
|
+
*/
|
|
68
|
+
exports.UNKNOWN_HARNESS_KEY = "unknown";
|
|
69
|
+
/**
|
|
70
|
+
* Session key for a caller with no session concept — an Agent SDK integration
|
|
71
|
+
* embedded in a long-running service, or a one-off script. Such a caller gets
|
|
72
|
+
* one stable identity under this key rather than a new client per call, which
|
|
73
|
+
* is the only sensible reading of "per session" when there are no sessions.
|
|
74
|
+
* Credentials migrated from a config written before session keying also land
|
|
75
|
+
* here: the session they belonged to is not recoverable, but the record stays
|
|
76
|
+
* addressable so uninstall can revoke it.
|
|
77
|
+
*/
|
|
78
|
+
exports.SESSIONLESS_KEY = "sessionless";
|
|
49
79
|
/**
|
|
50
80
|
* Single OS-agnostic data directory for *all* Ory agent plugin state:
|
|
51
81
|
* the shared config file, persisted DCR credentials, and any harness
|
|
@@ -116,6 +146,7 @@ function loadConfig() {
|
|
|
116
146
|
const parsed = JSON.parse(raw);
|
|
117
147
|
return {
|
|
118
148
|
projectUrl: typeof parsed.projectUrl === "string" ? parsed.projectUrl : undefined,
|
|
149
|
+
agentSecurityUrl: typeof parsed.agentSecurityUrl === "string" ? parsed.agentSecurityUrl : undefined,
|
|
119
150
|
projectId: typeof parsed.projectId === "string" && parsed.projectId.trim()
|
|
120
151
|
? parsed.projectId.trim()
|
|
121
152
|
: undefined,
|
|
@@ -125,16 +156,17 @@ function loadConfig() {
|
|
|
125
156
|
workspaceName: typeof parsed.workspaceName === "string" && parsed.workspaceName.trim()
|
|
126
157
|
? parsed.workspaceName.trim()
|
|
127
158
|
: undefined,
|
|
128
|
-
apiKey: typeof parsed.apiKey === "string" ? parsed.apiKey : undefined,
|
|
129
|
-
apiKeyId: typeof parsed.apiKeyId === "string" && parsed.apiKeyId.trim()
|
|
130
|
-
? parsed.apiKeyId.trim()
|
|
131
|
-
: undefined,
|
|
132
159
|
oauth2ClientId: typeof parsed.oauth2ClientId === "string" ? parsed.oauth2ClientId : undefined,
|
|
133
|
-
|
|
134
|
-
|
|
160
|
+
// NOTE: a `dxOnly` key written by an older release is deliberately not
|
|
161
|
+
// parsed. Whether Agent Security runs is derived from the presence of
|
|
162
|
+
// `projectUrl` + `oauth2ClientId` (see resolveConfig), never from a
|
|
163
|
+
// stored flag — so the stale key is simply dropped on the next write.
|
|
164
|
+
permissionModeCache: parsePermissionModeCache(parsed),
|
|
135
165
|
userSubjectNamespace: typeof parsed.userSubjectNamespace === "string" && parsed.userSubjectNamespace.trim()
|
|
136
166
|
? parsed.userSubjectNamespace.trim()
|
|
137
167
|
: undefined,
|
|
168
|
+
installedHarnesses: parseInstalledHarnesses(parsed.installedHarnesses),
|
|
169
|
+
delegationAnchors: parseDelegationAnchors(parsed.delegationAnchors),
|
|
138
170
|
user: parseUserCredentials(parsed),
|
|
139
171
|
agent: parseAgentCredentials(parsed),
|
|
140
172
|
};
|
|
@@ -143,32 +175,195 @@ function loadConfig() {
|
|
|
143
175
|
return {};
|
|
144
176
|
}
|
|
145
177
|
}
|
|
178
|
+
function parseDelegationAnchors(value) {
|
|
179
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
180
|
+
return undefined;
|
|
181
|
+
const result = {};
|
|
182
|
+
for (const [harness, rawSessions] of Object.entries(value)) {
|
|
183
|
+
if (!rawSessions || typeof rawSessions !== "object" || Array.isArray(rawSessions))
|
|
184
|
+
continue;
|
|
185
|
+
const sessions = {};
|
|
186
|
+
for (const [session, nodeId] of Object.entries(rawSessions)) {
|
|
187
|
+
if (typeof nodeId === "string" && nodeId.length > 0)
|
|
188
|
+
sessions[session] = nodeId;
|
|
189
|
+
}
|
|
190
|
+
if (Object.keys(sessions).length > 0)
|
|
191
|
+
result[harness] = sessions;
|
|
192
|
+
}
|
|
193
|
+
return Object.keys(result).length > 0 ? result : undefined;
|
|
194
|
+
}
|
|
146
195
|
function parsePermissionMode(value) {
|
|
147
196
|
return value === "observe" || value === "enforce" ? value : undefined;
|
|
148
197
|
}
|
|
198
|
+
/**
|
|
199
|
+
* Parse the persisted {@link PermissionModeCache}. Also migrates a legacy
|
|
200
|
+
* top-level `permissionMode` string (the old user-set field) into the cache so
|
|
201
|
+
* an upgrade preserves the last posture until the first server read overwrites
|
|
202
|
+
* it (`fetchedAt: 0` marks it as never-server-confirmed).
|
|
203
|
+
*/
|
|
204
|
+
function parsePermissionModeCache(parsed) {
|
|
205
|
+
const raw = parsed.permissionModeCache;
|
|
206
|
+
if (raw && typeof raw === "object") {
|
|
207
|
+
const obj = raw;
|
|
208
|
+
const mode = parsePermissionMode(obj.mode);
|
|
209
|
+
if (mode) {
|
|
210
|
+
const fetchedAt = typeof obj.fetchedAt === "number" ? obj.fetchedAt : 0;
|
|
211
|
+
const scopes = {};
|
|
212
|
+
if (obj.scopes && typeof obj.scopes === "object") {
|
|
213
|
+
for (const [key, value] of Object.entries(obj.scopes)) {
|
|
214
|
+
if (!value || typeof value !== "object")
|
|
215
|
+
continue;
|
|
216
|
+
const entry = value;
|
|
217
|
+
const entryMode = parsePermissionMode(entry.mode);
|
|
218
|
+
if (!entryMode)
|
|
219
|
+
continue;
|
|
220
|
+
scopes[key] = {
|
|
221
|
+
mode: entryMode,
|
|
222
|
+
fetchedAt: typeof entry.fetchedAt === "number" ? entry.fetchedAt : 0,
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
return {
|
|
227
|
+
mode,
|
|
228
|
+
fetchedAt,
|
|
229
|
+
...(typeof obj.projectUrl === "string" ? { projectUrl: obj.projectUrl } : {}),
|
|
230
|
+
...(Object.keys(scopes).length ? { scopes } : {}),
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
const legacy = parsePermissionMode(parsed.permissionMode);
|
|
235
|
+
if (legacy)
|
|
236
|
+
return { mode: legacy, fetchedAt: 0 };
|
|
237
|
+
return undefined;
|
|
238
|
+
}
|
|
149
239
|
function parseAgentCredentials(parsed) {
|
|
150
240
|
const raw = parsed.agent;
|
|
151
241
|
if (!raw || typeof raw !== "object")
|
|
152
242
|
return undefined;
|
|
153
243
|
const block = raw;
|
|
154
|
-
const
|
|
244
|
+
const retired = parseRetiredCredentials(block.retired);
|
|
245
|
+
const dynamic = parseAgentDynamicByHarness(block.dynamic);
|
|
155
246
|
const subAgents = parseSubAgentCredentials(block.subAgents);
|
|
156
|
-
if (!dynamic && !subAgents)
|
|
247
|
+
if (!dynamic && !subAgents && retired.length === 0)
|
|
157
248
|
return undefined;
|
|
158
249
|
return {
|
|
159
250
|
...(dynamic ? { dynamic } : {}),
|
|
160
251
|
...(subAgents ? { subAgents } : {}),
|
|
252
|
+
...(retired.length > 0 ? { retired } : {}),
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
function parseRetiredCredentials(value) {
|
|
256
|
+
if (!Array.isArray(value))
|
|
257
|
+
return [];
|
|
258
|
+
const out = [];
|
|
259
|
+
for (const entry of value) {
|
|
260
|
+
const creds = parseAgentDynamicCredentials(entry);
|
|
261
|
+
if (creds)
|
|
262
|
+
out.push(creds);
|
|
263
|
+
}
|
|
264
|
+
return out;
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* True when `value` is a credential record itself rather than a map of them.
|
|
268
|
+
* A credential record always carries a string `clientId`; a keyed map never
|
|
269
|
+
* does. This is what lets the parser accept both the current harness-keyed
|
|
270
|
+
* shape and the pre-migration flat shape without a version field.
|
|
271
|
+
*/
|
|
272
|
+
function looksLikeCredentialRecord(value) {
|
|
273
|
+
if (!value || typeof value !== "object")
|
|
274
|
+
return false;
|
|
275
|
+
return typeof value.clientId === "string";
|
|
276
|
+
}
|
|
277
|
+
/**
|
|
278
|
+
* Parse `agent.dynamic` into `{ [harness]: { [session]: creds } }`.
|
|
279
|
+
*
|
|
280
|
+
* Three shapes have existed, and each is recognizable without a version field
|
|
281
|
+
* because only a credential record carries a string `clientId`:
|
|
282
|
+
*
|
|
283
|
+
* 1. one bare record — pre-harness keying
|
|
284
|
+
* 2. `{ [harness]: creds }` — install-scoped release
|
|
285
|
+
* 3. `{ [harness]: { [session]: creds } }` — current
|
|
286
|
+
*
|
|
287
|
+
* Records without a known session migrate to {@link SESSIONLESS_KEY}.
|
|
288
|
+
*/
|
|
289
|
+
function parseAgentDynamicByHarness(value) {
|
|
290
|
+
if (!value || typeof value !== "object")
|
|
291
|
+
return undefined;
|
|
292
|
+
const result = {};
|
|
293
|
+
const put = (harness, session, creds) => {
|
|
294
|
+
(result[harness] ??= {})[session] = creds;
|
|
161
295
|
};
|
|
296
|
+
// Shape 1: a single bare record, re-keyed under the harness it names.
|
|
297
|
+
if (looksLikeCredentialRecord(value)) {
|
|
298
|
+
const legacy = parseAgentDynamicCredentials(value);
|
|
299
|
+
if (!legacy)
|
|
300
|
+
return undefined;
|
|
301
|
+
put(legacy.harness ?? exports.UNKNOWN_HARNESS_KEY, exports.SESSIONLESS_KEY, legacy);
|
|
302
|
+
return result;
|
|
303
|
+
}
|
|
304
|
+
for (const [harness, raw] of Object.entries(value)) {
|
|
305
|
+
// Shape 2: harness → one install-scoped record.
|
|
306
|
+
if (looksLikeCredentialRecord(raw)) {
|
|
307
|
+
const creds = parseAgentDynamicCredentials(raw);
|
|
308
|
+
if (creds)
|
|
309
|
+
put(harness, exports.SESSIONLESS_KEY, creds);
|
|
310
|
+
continue;
|
|
311
|
+
}
|
|
312
|
+
// Shape 3: harness → session → record.
|
|
313
|
+
if (!raw || typeof raw !== "object")
|
|
314
|
+
continue;
|
|
315
|
+
for (const [session, entry] of Object.entries(raw)) {
|
|
316
|
+
const creds = parseAgentDynamicCredentials(entry);
|
|
317
|
+
if (creds)
|
|
318
|
+
put(harness, session, creds);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
return Object.keys(result).length > 0 ? result : undefined;
|
|
162
322
|
}
|
|
323
|
+
/**
|
|
324
|
+
* Parse `agent.subAgents` into
|
|
325
|
+
* `{ [harness]: { [session]: { [type]: creds } } }`.
|
|
326
|
+
*
|
|
327
|
+
* As with `agent.dynamic`, three shapes have existed:
|
|
328
|
+
*
|
|
329
|
+
* 1. `{ [type]: creds }` — pre-harness keying
|
|
330
|
+
* 2. `{ [harness]: { [type]: creds } }` — install-scoped release
|
|
331
|
+
* 3. `{ [harness]: { [session]: { [type]: creds } } }` — current
|
|
332
|
+
*/
|
|
163
333
|
function parseSubAgentCredentials(value) {
|
|
164
334
|
if (!value || typeof value !== "object")
|
|
165
335
|
return undefined;
|
|
166
|
-
const entries = value;
|
|
167
336
|
const result = {};
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
337
|
+
const put = (harness, session, subAgentType, creds) => {
|
|
338
|
+
((result[harness] ??= {})[session] ??= {})[subAgentType] = creds;
|
|
339
|
+
};
|
|
340
|
+
for (const [key, raw] of Object.entries(value)) {
|
|
341
|
+
// Shape 1: `key` is the sub-agent type; the harness comes from the record.
|
|
342
|
+
if (looksLikeCredentialRecord(raw)) {
|
|
343
|
+
const creds = parseAgentDynamicCredentials(raw);
|
|
344
|
+
if (creds)
|
|
345
|
+
put(creds.harness ?? exports.UNKNOWN_HARNESS_KEY, exports.SESSIONLESS_KEY, key, creds);
|
|
346
|
+
continue;
|
|
347
|
+
}
|
|
348
|
+
if (!raw || typeof raw !== "object")
|
|
349
|
+
continue;
|
|
350
|
+
for (const [inner, entry] of Object.entries(raw)) {
|
|
351
|
+
// Shape 2: `inner` is the sub-agent type, sitting directly under harness.
|
|
352
|
+
if (looksLikeCredentialRecord(entry)) {
|
|
353
|
+
const creds = parseAgentDynamicCredentials(entry);
|
|
354
|
+
if (creds)
|
|
355
|
+
put(key, exports.SESSIONLESS_KEY, inner, creds);
|
|
356
|
+
continue;
|
|
357
|
+
}
|
|
358
|
+
// Shape 3: `inner` is the session.
|
|
359
|
+
if (!entry || typeof entry !== "object")
|
|
360
|
+
continue;
|
|
361
|
+
for (const [subAgentType, leaf] of Object.entries(entry)) {
|
|
362
|
+
const creds = parseAgentDynamicCredentials(leaf);
|
|
363
|
+
if (creds)
|
|
364
|
+
put(key, inner, subAgentType, creds);
|
|
365
|
+
}
|
|
366
|
+
}
|
|
172
367
|
}
|
|
173
368
|
return Object.keys(result).length > 0 ? result : undefined;
|
|
174
369
|
}
|
|
@@ -192,8 +387,33 @@ function parseAgentDynamicCredentials(value) {
|
|
|
192
387
|
...(parseDelegationRecord(v.delegation)
|
|
193
388
|
? { delegation: parseDelegationRecord(v.delegation) }
|
|
194
389
|
: {}),
|
|
390
|
+
...(parseDelegationNodeIds(v.delegationNodeIds, v.delegationNodeId)
|
|
391
|
+
? { delegationNodeIds: parseDelegationNodeIds(v.delegationNodeIds, v.delegationNodeId) }
|
|
392
|
+
: {}),
|
|
195
393
|
};
|
|
196
394
|
}
|
|
395
|
+
/**
|
|
396
|
+
* Parse the per-session delegation node map, migrating the single
|
|
397
|
+
* `delegationNodeId` field earlier releases wrote.
|
|
398
|
+
*
|
|
399
|
+
* A migrated scalar lands under {@link SESSIONLESS_KEY}: the session it was
|
|
400
|
+
* recorded in was never persisted alongside it, and guessing would attribute a
|
|
401
|
+
* sub-agent to the wrong run. Landing it there means the next session records
|
|
402
|
+
* its own node id rather than inheriting a stale one — the correct outcome,
|
|
403
|
+
* since the node id is cheap to re-obtain (the broker's write is idempotent).
|
|
404
|
+
*/
|
|
405
|
+
function parseDelegationNodeIds(value, legacy) {
|
|
406
|
+
const result = {};
|
|
407
|
+
if (typeof legacy === "string" && legacy.length > 0)
|
|
408
|
+
result[exports.SESSIONLESS_KEY] = legacy;
|
|
409
|
+
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
410
|
+
for (const [session, nodeId] of Object.entries(value)) {
|
|
411
|
+
if (typeof nodeId === "string" && nodeId.length > 0)
|
|
412
|
+
result[session] = nodeId;
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
return Object.keys(result).length > 0 ? result : undefined;
|
|
416
|
+
}
|
|
197
417
|
function parseDelegationRecord(value) {
|
|
198
418
|
if (!value || typeof value !== "object")
|
|
199
419
|
return undefined;
|
|
@@ -211,6 +431,57 @@ function parseDelegationRecord(value) {
|
|
|
211
431
|
delegatedAt: typeof v.delegatedAt === "string" ? v.delegatedAt : "",
|
|
212
432
|
};
|
|
213
433
|
}
|
|
434
|
+
function parseInstalledHarnesses(value) {
|
|
435
|
+
if (!Array.isArray(value))
|
|
436
|
+
return undefined;
|
|
437
|
+
const names = normalizeHarnessList(value.filter((v) => typeof v === "string"));
|
|
438
|
+
return names.length > 0 ? names : undefined;
|
|
439
|
+
}
|
|
440
|
+
/** De-duplicate, trim, and sort a harness list so the file stays stable. */
|
|
441
|
+
function normalizeHarnessList(names) {
|
|
442
|
+
return [...new Set(names.map((n) => n.trim()).filter((n) => n.length > 0))].sort();
|
|
443
|
+
}
|
|
444
|
+
/**
|
|
445
|
+
* The harness plugins recorded as installed against this shared config.
|
|
446
|
+
* Returns an empty array when nothing has been registered yet (which, on a
|
|
447
|
+
* config written before the registry existed, is not the same as "nothing is
|
|
448
|
+
* installed" — callers that must not over-read that should reconcile against
|
|
449
|
+
* the runtime manifest and persisted credentials; see
|
|
450
|
+
* `resolveInstalledHarnesses` in `uninstall.ts`).
|
|
451
|
+
*/
|
|
452
|
+
function listInstalledHarnesses() {
|
|
453
|
+
return loadConfig().installedHarnesses ?? [];
|
|
454
|
+
}
|
|
455
|
+
/**
|
|
456
|
+
* Record a harness plugin as installed. Idempotent — installing twice leaves
|
|
457
|
+
* one entry. Returns the full list after the addition.
|
|
458
|
+
*/
|
|
459
|
+
function registerInstalledHarness(harness) {
|
|
460
|
+
let result = [];
|
|
461
|
+
mutateConfig((current) => {
|
|
462
|
+
result = normalizeHarnessList([...(current.installedHarnesses ?? []), harness]);
|
|
463
|
+
return { ...current, installedHarnesses: result };
|
|
464
|
+
});
|
|
465
|
+
return result;
|
|
466
|
+
}
|
|
467
|
+
/**
|
|
468
|
+
* Forget a harness plugin. Returns the harnesses still installed afterwards —
|
|
469
|
+
* what the uninstall path uses to decide whether the shared config is now
|
|
470
|
+
* unreferenced and safe to wipe.
|
|
471
|
+
*/
|
|
472
|
+
function unregisterInstalledHarness(harness) {
|
|
473
|
+
let result = [];
|
|
474
|
+
mutateConfig((current) => {
|
|
475
|
+
result = normalizeHarnessList(current.installedHarnesses ?? []).filter((h) => h !== harness.trim());
|
|
476
|
+
const next = { ...current };
|
|
477
|
+
if (result.length > 0)
|
|
478
|
+
next.installedHarnesses = result;
|
|
479
|
+
else
|
|
480
|
+
delete next.installedHarnesses;
|
|
481
|
+
return next;
|
|
482
|
+
});
|
|
483
|
+
return result;
|
|
484
|
+
}
|
|
214
485
|
function parseUserCredentials(parsed) {
|
|
215
486
|
// Prefer the new nested shape; fall back to the legacy root-level
|
|
216
487
|
// `oauth2` block so configs written before the user/agent split still
|
|
@@ -236,9 +507,6 @@ function parseOAuth2(value) {
|
|
|
236
507
|
refreshToken: typeof v.refreshToken === "string" ? v.refreshToken : undefined,
|
|
237
508
|
expiresAt: v.expiresAt,
|
|
238
509
|
subject: typeof v.subject === "string" ? v.subject : undefined,
|
|
239
|
-
clientId: typeof v.clientId === "string" ? v.clientId : undefined,
|
|
240
|
-
idToken: typeof v.idToken === "string" ? v.idToken : undefined,
|
|
241
|
-
scope: typeof v.scope === "string" ? v.scope : undefined,
|
|
242
510
|
};
|
|
243
511
|
}
|
|
244
512
|
/**
|
|
@@ -265,7 +533,8 @@ function mutateConfig(mutator) {
|
|
|
265
533
|
try {
|
|
266
534
|
const existing = loadConfig();
|
|
267
535
|
const next = mutator(existing);
|
|
268
|
-
|
|
536
|
+
if (next)
|
|
537
|
+
writeConfigAtomic(next);
|
|
269
538
|
}
|
|
270
539
|
finally {
|
|
271
540
|
releaseLock(lock);
|
|
@@ -384,9 +653,101 @@ function releaseLock(lock) {
|
|
|
384
653
|
function writeConfigAtomic(config) {
|
|
385
654
|
const target = configFile();
|
|
386
655
|
const tmp = `${target}.${process.pid}.${Date.now()}.tmp`;
|
|
387
|
-
fs.writeFileSync(tmp, JSON.stringify(config, null, 2) + "\n", {
|
|
656
|
+
fs.writeFileSync(tmp, JSON.stringify(compactPersistedConfig(config), null, 2) + "\n", {
|
|
657
|
+
mode: 0o600,
|
|
658
|
+
});
|
|
388
659
|
fs.renameSync(tmp, target);
|
|
389
660
|
}
|
|
661
|
+
/**
|
|
662
|
+
* Keep only state that cannot be reconstructed safely in a later process.
|
|
663
|
+
* This is the one persistence boundary, so old verbose records are compacted
|
|
664
|
+
* by any subsequent config mutation regardless of which subsystem writes.
|
|
665
|
+
*/
|
|
666
|
+
function compactPersistedConfig(config) {
|
|
667
|
+
const userTokens = config.user?.oauth2;
|
|
668
|
+
const user = userTokens
|
|
669
|
+
? {
|
|
670
|
+
oauth2: {
|
|
671
|
+
accessToken: userTokens.accessToken,
|
|
672
|
+
...(userTokens.refreshToken ? { refreshToken: userTokens.refreshToken } : {}),
|
|
673
|
+
expiresAt: userTokens.expiresAt,
|
|
674
|
+
...(userTokens.subject ? { subject: userTokens.subject } : {}),
|
|
675
|
+
},
|
|
676
|
+
}
|
|
677
|
+
: undefined;
|
|
678
|
+
const active = (creds) => ({
|
|
679
|
+
clientId: creds.clientId,
|
|
680
|
+
...(creds.clientSecret ? { clientSecret: creds.clientSecret } : {}),
|
|
681
|
+
...(creds.registrationAccessToken
|
|
682
|
+
? { registrationAccessToken: creds.registrationAccessToken }
|
|
683
|
+
: {}),
|
|
684
|
+
...(creds.registrationClientUri
|
|
685
|
+
? { registrationClientUri: creds.registrationClientUri }
|
|
686
|
+
: {}),
|
|
687
|
+
registeredAt: creds.registeredAt,
|
|
688
|
+
projectUrl: creds.projectUrl,
|
|
689
|
+
...(creds.delegation
|
|
690
|
+
? {
|
|
691
|
+
delegation: {
|
|
692
|
+
delegatedBy: creds.delegation.delegatedBy,
|
|
693
|
+
delegationType: creds.delegation.delegationType,
|
|
694
|
+
},
|
|
695
|
+
}
|
|
696
|
+
: {}),
|
|
697
|
+
...(creds.delegationNodeIds
|
|
698
|
+
? { delegationNodeIds: creds.delegationNodeIds }
|
|
699
|
+
: {}),
|
|
700
|
+
});
|
|
701
|
+
const dynamic = config.agent?.dynamic
|
|
702
|
+
? Object.fromEntries(Object.entries(config.agent.dynamic).map(([harness, sessions]) => [
|
|
703
|
+
harness,
|
|
704
|
+
Object.fromEntries(Object.entries(sessions).map(([session, creds]) => [session, active(creds)])),
|
|
705
|
+
]))
|
|
706
|
+
: undefined;
|
|
707
|
+
const subAgents = config.agent?.subAgents
|
|
708
|
+
? Object.fromEntries(Object.entries(config.agent.subAgents).map(([harness, sessions]) => [
|
|
709
|
+
harness,
|
|
710
|
+
Object.fromEntries(Object.entries(sessions).map(([session, byType]) => [
|
|
711
|
+
session,
|
|
712
|
+
Object.fromEntries(Object.entries(byType).map(([type, creds]) => [type, active(creds)])),
|
|
713
|
+
])),
|
|
714
|
+
]))
|
|
715
|
+
: undefined;
|
|
716
|
+
const retired = config.agent?.retired?.map((creds) => ({
|
|
717
|
+
clientId: creds.clientId,
|
|
718
|
+
projectUrl: creds.projectUrl,
|
|
719
|
+
...(creds.harness ? { harness: creds.harness } : {}),
|
|
720
|
+
...(creds.registrationAccessToken
|
|
721
|
+
? { registrationAccessToken: creds.registrationAccessToken }
|
|
722
|
+
: {}),
|
|
723
|
+
...(creds.registrationClientUri
|
|
724
|
+
? { registrationClientUri: creds.registrationClientUri }
|
|
725
|
+
: {}),
|
|
726
|
+
}));
|
|
727
|
+
const agent = dynamic || subAgents || retired?.length
|
|
728
|
+
? {
|
|
729
|
+
...(dynamic ? { dynamic } : {}),
|
|
730
|
+
...(subAgents ? { subAgents } : {}),
|
|
731
|
+
...(retired?.length ? { retired } : {}),
|
|
732
|
+
}
|
|
733
|
+
: undefined;
|
|
734
|
+
return {
|
|
735
|
+
...(config.projectUrl ? { projectUrl: config.projectUrl } : {}),
|
|
736
|
+
...(config.agentSecurityUrl ? { agentSecurityUrl: config.agentSecurityUrl } : {}),
|
|
737
|
+
...(config.projectId ? { projectId: config.projectId } : {}),
|
|
738
|
+
...(config.oauth2ClientId ? { oauth2ClientId: config.oauth2ClientId } : {}),
|
|
739
|
+
...(config.permissionModeCache ? { permissionModeCache: config.permissionModeCache } : {}),
|
|
740
|
+
...(config.userSubjectNamespace
|
|
741
|
+
? { userSubjectNamespace: config.userSubjectNamespace }
|
|
742
|
+
: {}),
|
|
743
|
+
...(config.installedHarnesses?.length
|
|
744
|
+
? { installedHarnesses: config.installedHarnesses }
|
|
745
|
+
: {}),
|
|
746
|
+
...(config.delegationAnchors ? { delegationAnchors: config.delegationAnchors } : {}),
|
|
747
|
+
...(user ? { user } : {}),
|
|
748
|
+
...(agent ? { agent } : {}),
|
|
749
|
+
};
|
|
750
|
+
}
|
|
390
751
|
/** Matches an Ory project UUID (the value `ORY_PROJECT_ID` carries). */
|
|
391
752
|
const PROJECT_ID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
392
753
|
/**
|
|
@@ -402,6 +763,47 @@ const PROJECT_ID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]
|
|
|
402
763
|
function looksLikeProjectId(value) {
|
|
403
764
|
return PROJECT_ID_RE.test(value.trim());
|
|
404
765
|
}
|
|
766
|
+
/** Reserved public PKCE client provisioned by Ory Agent Security setup. */
|
|
767
|
+
exports.DEFAULT_OAUTH2_CLIENT_ID = "ory-agent-security-login";
|
|
768
|
+
exports.DEFAULT_AGENT_SECURITY_URL = "https://agents.console.ory.com";
|
|
769
|
+
exports.LOCAL_AGENT_SECURITY_URL = "https://agents.console.ory:8080";
|
|
770
|
+
function resolveSecurityConnection(projectUrl, agentSecurityUrl, oauth2ClientId) {
|
|
771
|
+
const missing = [];
|
|
772
|
+
if (!projectUrl?.trim())
|
|
773
|
+
missing.push("projectUrl");
|
|
774
|
+
if (!agentSecurityUrl?.trim())
|
|
775
|
+
missing.push("agentSecurityUrl");
|
|
776
|
+
if (!oauth2ClientId?.trim())
|
|
777
|
+
missing.push("oauth2ClientId");
|
|
778
|
+
return { connected: missing.length === 0, missing };
|
|
779
|
+
}
|
|
780
|
+
/**
|
|
781
|
+
* The one predicate the gates ask: is Agent Security connected?
|
|
782
|
+
*
|
|
783
|
+
* Shorthand for `resolveConfig().security.connected`, provided so the many
|
|
784
|
+
* call sites that only need the boolean read as a single question rather than
|
|
785
|
+
* a property walk. When this is false the plugin still runs — it just logs activity
|
|
786
|
+
* locally and gates nothing.
|
|
787
|
+
*/
|
|
788
|
+
function isSecurityConnected() {
|
|
789
|
+
return resolveConfig().security.connected;
|
|
790
|
+
}
|
|
791
|
+
/** The CLI flag / env var a user sets for each required value. */
|
|
792
|
+
const SECURITY_VALUE_LABELS = {
|
|
793
|
+
projectUrl: "--project-url (ORY_PROJECT_URL)",
|
|
794
|
+
agentSecurityUrl: "--agent-security-url (ORY_AGENT_SECURITY_URL)",
|
|
795
|
+
oauth2ClientId: "--oauth2-client-id (ORY_OAUTH2_CLIENT_ID)",
|
|
796
|
+
};
|
|
797
|
+
/**
|
|
798
|
+
* Render why Agent Security isn't running, e.g.
|
|
799
|
+
* `"missing --oauth2-client-id (ORY_OAUTH2_CLIENT_ID)"`. Returns undefined when
|
|
800
|
+
* it *is* connected, so callers can `?? "connected"` at the display site.
|
|
801
|
+
*/
|
|
802
|
+
function describeSecurityGap(security = resolveConfig().security) {
|
|
803
|
+
if (security.connected)
|
|
804
|
+
return undefined;
|
|
805
|
+
return `missing ${security.missing.map((m) => SECURITY_VALUE_LABELS[m]).join(" and ")}`;
|
|
806
|
+
}
|
|
405
807
|
/**
|
|
406
808
|
* Resolve config by checking environment variables first, then the config file.
|
|
407
809
|
* Returns the merged result with the source of each value.
|
|
@@ -416,20 +818,17 @@ function resolveConfig() {
|
|
|
416
818
|
// ORY_PROJECT_URL is the documented name; ORY_SDK_URL is the name the Ory
|
|
417
819
|
// Console "Get Started" panel and the Ory SDKs use — accepted as an alias.
|
|
418
820
|
const envProjectUrl = process.env.ORY_PROJECT_URL?.trim() || process.env.ORY_SDK_URL?.trim() || undefined;
|
|
821
|
+
const envAgentSecurityUrl = process.env.ORY_AGENT_SECURITY_URL?.trim() || undefined;
|
|
419
822
|
const envProjectId = process.env.ORY_PROJECT_ID?.trim() || undefined;
|
|
420
|
-
|
|
421
|
-
// alias kept for back-compat (agent-auth emits a warning when only the
|
|
422
|
-
// legacy form is set).
|
|
423
|
-
const envApiKey = process.env.ORY_AGENT_API_KEY ?? process.env.ORY_API_KEY;
|
|
424
|
-
const envClientId = process.env.ORY_OAUTH2_CLIENT_ID;
|
|
425
|
-
const envMode = parsePermissionMode(process.env.ORY_PERMISSION_MODE);
|
|
823
|
+
const envClientId = process.env.ORY_OAUTH2_CLIENT_ID?.trim() || undefined;
|
|
426
824
|
const envUserSubjectNamespace = process.env.ORY_USER_SUBJECT_NAMESPACE?.trim() || undefined;
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
825
|
+
// The mode is server-controlled (a Keto permission read per-check by
|
|
826
|
+
// resolvePermissionMode). Here we only surface the last cached value for the
|
|
827
|
+
// synchronous read path; there is no env or local override.
|
|
828
|
+
const permissionMode = file.permissionModeCache?.mode ?? "observe";
|
|
829
|
+
const permissionModeSource = file.permissionModeCache
|
|
830
|
+
? "cache"
|
|
831
|
+
: "default";
|
|
433
832
|
const projectId = envProjectId ?? file.projectId;
|
|
434
833
|
// The SDK URL is only ever an explicit, slug-based URL (from ORY_PROJECT_URL,
|
|
435
834
|
// ORY_SDK_URL, or the config file). The project id is NOT a URL source — it
|
|
@@ -440,16 +839,33 @@ function resolveConfig() {
|
|
|
440
839
|
: file.projectUrl
|
|
441
840
|
? "config"
|
|
442
841
|
: "none";
|
|
842
|
+
// Preserve the project URL fallback only for persisted pre-default configs.
|
|
843
|
+
// New env-only and configure flows use the production default unless they
|
|
844
|
+
// explicitly select staging, local, or a custom broker.
|
|
845
|
+
const legacyAgentSecurityUrl = !envProjectUrl && file.projectUrl?.trim() && !file.agentSecurityUrl ? file.projectUrl.trim() : undefined;
|
|
846
|
+
const agentSecurityUrl = envAgentSecurityUrl ?? file.agentSecurityUrl ?? legacyAgentSecurityUrl ?? exports.DEFAULT_AGENT_SECURITY_URL;
|
|
847
|
+
const agentSecurityUrlSource = envAgentSecurityUrl
|
|
848
|
+
? "env"
|
|
849
|
+
: file.agentSecurityUrl
|
|
850
|
+
? "config"
|
|
851
|
+
: legacyAgentSecurityUrl
|
|
852
|
+
? "projectUrl"
|
|
853
|
+
: "default";
|
|
854
|
+
const fileClientId = file.oauth2ClientId?.trim() || undefined;
|
|
855
|
+
const oauth2ClientId = envClientId ?? fileClientId ?? exports.DEFAULT_OAUTH2_CLIENT_ID;
|
|
443
856
|
return {
|
|
444
857
|
projectUrl,
|
|
858
|
+
agentSecurityUrl,
|
|
445
859
|
projectId,
|
|
446
860
|
projectName: file.projectName,
|
|
447
861
|
workspaceName: file.workspaceName,
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
862
|
+
oauth2ClientId,
|
|
863
|
+
// Agent Security runs exactly when all resolved values it needs are present.
|
|
864
|
+
// The broker origin can resolve through the legacy project URL fallback.
|
|
865
|
+
security: resolveSecurityConnection(projectUrl, agentSecurityUrl, oauth2ClientId),
|
|
451
866
|
permissionMode,
|
|
452
867
|
permissionModeSource,
|
|
868
|
+
permissionModeCache: file.permissionModeCache,
|
|
453
869
|
userSubjectNamespace: envUserSubjectNamespace ?? file.userSubjectNamespace,
|
|
454
870
|
userSubjectNamespaceSource: envUserSubjectNamespace
|
|
455
871
|
? "env"
|
|
@@ -457,22 +873,25 @@ function resolveConfig() {
|
|
|
457
873
|
? "config"
|
|
458
874
|
: "none",
|
|
459
875
|
projectUrlSource,
|
|
876
|
+
agentSecurityUrlSource,
|
|
460
877
|
projectIdSource: envProjectId ? "env" : file.projectId ? "config" : "none",
|
|
461
|
-
|
|
462
|
-
oauth2ClientIdSource: envClientId ? "env" : file.oauth2ClientId ? "config" : "none",
|
|
878
|
+
oauth2ClientIdSource: envClientId ? "env" : fileClientId ? "config" : "default",
|
|
463
879
|
};
|
|
464
880
|
}
|
|
465
881
|
/**
|
|
466
|
-
* Build the "not
|
|
882
|
+
* Build the "Agent Security is not connected" message for a harness CLI.
|
|
883
|
+
*
|
|
884
|
+
* Deliberately does not frame this as a degraded mode: the plugin is fully
|
|
885
|
+
* installed and its developer-experience half is working. The message states
|
|
886
|
+
* the one thing that is off and the values that turn it on.
|
|
467
887
|
*/
|
|
468
888
|
function configPromptMessage(binName) {
|
|
469
|
-
return ("
|
|
470
|
-
"\n" +
|
|
471
|
-
"
|
|
472
|
-
` ${(0, cli_invocation_js_1.oryNpx)(binName)} configure --project-url <URL> --oauth2-client-id <CLIENT_ID> [--api-key <KEY>]\n` +
|
|
889
|
+
return ("Ory Agent Security is not connected, so no sign-in or permission checks\n" +
|
|
890
|
+
"run. Everything else the plugin installs — skills, commands, the local Ory\n" +
|
|
891
|
+
"stack, the MCP server, and local activity logging — works as it is.\n" +
|
|
473
892
|
"\n" +
|
|
474
|
-
"
|
|
475
|
-
` ${(0, cli_invocation_js_1.oryNpx)(binName)} configure --
|
|
893
|
+
" Connect it with the values from the Ory Console (Agent Security):\n" +
|
|
894
|
+
` ${(0, cli_invocation_js_1.oryNpx)(binName)} configure --project-url <URL>\n` +
|
|
476
895
|
"\n" +
|
|
477
896
|
`Configuration is saved to ${configFile()} and shared across all agent plugins.`);
|
|
478
897
|
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { RuntimeCredential } from "./runtime-credential.js";
|
|
2
|
+
export interface SessionContext {
|
|
3
|
+
sessionId?: string;
|
|
4
|
+
runtimeCredential?: RuntimeCredential;
|
|
5
|
+
}
|
|
6
|
+
export declare function currentSessionContext(): Readonly<SessionContext>;
|
|
7
|
+
export declare function withSessionContext<T>(context: SessionContext, work: () => T): T;
|
|
8
|
+
/** Test and low-level integration helper. Prefer `withHookContext` in adapters. */
|
|
9
|
+
export declare function setSessionContext(context: SessionContext): void;
|
|
10
|
+
export declare function clearSessionContext(): void;
|
package/dist/context.js
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.currentSessionContext = currentSessionContext;
|
|
4
|
+
exports.withSessionContext = withSessionContext;
|
|
5
|
+
exports.setSessionContext = setSessionContext;
|
|
6
|
+
exports.clearSessionContext = clearSessionContext;
|
|
7
|
+
const node_async_hooks_1 = require("node:async_hooks");
|
|
8
|
+
const sessionStorage = new node_async_hooks_1.AsyncLocalStorage();
|
|
9
|
+
function currentSessionContext() {
|
|
10
|
+
return sessionStorage.getStore() ?? {};
|
|
11
|
+
}
|
|
12
|
+
function withSessionContext(context, work) {
|
|
13
|
+
return sessionStorage.run({ ...currentSessionContext(), ...context }, work);
|
|
14
|
+
}
|
|
15
|
+
/** Test and low-level integration helper. Prefer `withHookContext` in adapters. */
|
|
16
|
+
function setSessionContext(context) {
|
|
17
|
+
sessionStorage.enterWith({ ...context });
|
|
18
|
+
}
|
|
19
|
+
function clearSessionContext() {
|
|
20
|
+
sessionStorage.enterWith({});
|
|
21
|
+
}
|