@seclai/sdk 1.1.2 → 1.1.4

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 CHANGED
@@ -51,7 +51,7 @@ Credentials are resolved via a chain (first match wins):
51
51
  1. Explicit `apiKey` option
52
52
  2. Explicit `accessToken` option (string or `() => string | Promise<string>`)
53
53
  3. `SECLAI_API_KEY` environment variable
54
- 4. SSO profile from `~/.seclai/config` with cached tokens in `~/.seclai/sso/cache/`
54
+ 4. SSO cached tokens from `~/.seclai/sso/cache/` (requires a prior `seclai auth login`)
55
55
 
56
56
  ```ts
57
57
  // API key
@@ -81,18 +81,30 @@ const client = new Seclai({ profile: "my-profile" });
81
81
  const client = new Seclai();
82
82
  ```
83
83
 
84
- To set up SSO authentication, install the [Seclai CLI](https://www.npmjs.com/package/seclai) and run:
84
+ #### SSO authentication
85
+
86
+ SSO is the default fallback when no explicit credentials are provided. The SDK
87
+ includes built-in production SSO defaults, so `seclai configure sso` is not
88
+ required. You only need to log in once to populate the token cache:
85
89
 
86
90
  ```bash
87
- seclai configure sso # set up an SSO profile
88
- seclai auth login # authenticate via browser
91
+ npx @seclai/cli auth login # authenticate via browser no prior setup needed
89
92
  ```
90
93
 
94
+ To customize SSO settings (e.g. for a staging environment), use `seclai configure sso`
95
+ or set environment variables:
96
+
97
+ | Variable | Description | Default |
98
+ |---|---|---|
99
+ | `SECLAI_SSO_DOMAIN` | Cognito domain | `auth.seclai.com` |
100
+ | `SECLAI_SSO_CLIENT_ID` | Cognito app client ID | `4bgf8v9qmc5puivbaqon9n5lmr` |
101
+ | `SECLAI_SSO_REGION` | AWS region | `us-west-2` |
102
+
91
103
  ## API documentation
92
104
 
93
105
  Online API documentation (latest):
94
106
 
95
- https://seclai.github.io/seclai-javascript/1.1.2/
107
+ https://seclai.github.io/seclai-javascript/1.1.4/
96
108
 
97
109
  ## Resources
98
110
 
package/dist/index.cjs CHANGED
@@ -30,13 +30,21 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
30
  // src/index.ts
31
31
  var index_exports = {};
32
32
  __export(index_exports, {
33
+ DEFAULT_SSO_CLIENT_ID: () => DEFAULT_SSO_CLIENT_ID,
34
+ DEFAULT_SSO_DOMAIN: () => DEFAULT_SSO_DOMAIN,
35
+ DEFAULT_SSO_REGION: () => DEFAULT_SSO_REGION,
33
36
  SECLAI_API_URL: () => SECLAI_API_URL,
34
37
  Seclai: () => Seclai,
35
38
  SeclaiAPIStatusError: () => SeclaiAPIStatusError,
36
39
  SeclaiAPIValidationError: () => SeclaiAPIValidationError,
37
40
  SeclaiConfigurationError: () => SeclaiConfigurationError,
38
41
  SeclaiError: () => SeclaiError,
39
- SeclaiStreamingError: () => SeclaiStreamingError
42
+ SeclaiStreamingError: () => SeclaiStreamingError,
43
+ deleteSsoCache: () => deleteSsoCache,
44
+ isTokenValid: () => isTokenValid,
45
+ loadSsoProfile: () => loadSsoProfile,
46
+ readSsoCache: () => readSsoCache,
47
+ writeSsoCache: () => writeSsoCache
40
48
  });
41
49
  module.exports = __toCommonJS(index_exports);
42
50
 
@@ -96,6 +104,9 @@ var SSO_CACHE_DIR = "sso/cache";
96
104
  var CONFIG_FILE = "config";
97
105
  var EXPIRY_BUFFER_MS = 3e4;
98
106
  var DEFAULT_API_KEY_HEADER = "x-api-key";
107
+ var DEFAULT_SSO_DOMAIN = "auth.seclai.com";
108
+ var DEFAULT_SSO_CLIENT_ID = "4bgf8v9qmc5puivbaqon9n5lmr";
109
+ var DEFAULT_SSO_REGION = "us-west-2";
99
110
  function getEnv(name) {
100
111
  const p = globalThis?.process;
101
112
  return p?.env?.[name];
@@ -169,19 +180,21 @@ async function resolveConfigDir(override) {
169
180
  async function loadSsoProfile(configDir, profileName) {
170
181
  const fs = await getFs();
171
182
  const pathMod = await getPath();
183
+ let merged = {};
172
184
  const configPath = pathMod.join(configDir, CONFIG_FILE);
173
- if (!fs.existsSync(configPath)) return null;
174
- const content = fs.readFileSync(configPath, "utf-8");
175
- const sections = parseIni(content);
176
- const defaultSection = sections["default"] ?? {};
177
- const profileSection = profileName === "default" ? defaultSection : sections[profileName];
178
- if (!profileSection) return null;
179
- const merged = profileName === "default" ? profileSection : { ...defaultSection, ...profileSection };
180
- const ssoAccountId = merged["sso_account_id"];
181
- const ssoRegion = merged["sso_region"];
182
- const ssoClientId = merged["sso_client_id"];
183
- const ssoDomain = merged["sso_domain"];
184
- if (!ssoAccountId || !ssoRegion || !ssoClientId || !ssoDomain) return null;
185
+ if (fs.existsSync(configPath)) {
186
+ const content = fs.readFileSync(configPath, "utf-8");
187
+ const sections = parseIni(content);
188
+ const defaultSection = sections["default"] ?? {};
189
+ const profileSection = profileName === "default" ? defaultSection : sections[profileName];
190
+ if (profileSection) {
191
+ merged = profileName === "default" ? profileSection : { ...defaultSection, ...profileSection };
192
+ }
193
+ }
194
+ const ssoDomain = getEnv("SECLAI_SSO_DOMAIN") ?? merged["sso_domain"] ?? DEFAULT_SSO_DOMAIN;
195
+ const ssoClientId = getEnv("SECLAI_SSO_CLIENT_ID") ?? merged["sso_client_id"] ?? DEFAULT_SSO_CLIENT_ID;
196
+ const ssoRegion = getEnv("SECLAI_SSO_REGION") ?? merged["sso_region"] ?? DEFAULT_SSO_REGION;
197
+ const ssoAccountId = merged["sso_account_id"] || void 0;
185
198
  return { ssoAccountId, ssoRegion, ssoClientId, ssoDomain };
186
199
  }
187
200
  async function resolveCachePath(configDir, profile) {
@@ -216,6 +229,13 @@ async function writeSsoCache(configDir, profile, entry) {
216
229
  }
217
230
  fs.renameSync(tmpPath, cachePath);
218
231
  }
232
+ async function deleteSsoCache(configDir, profile) {
233
+ const fs = await getFs();
234
+ const cachePath = await resolveCachePath(configDir, profile);
235
+ if (fs.existsSync(cachePath)) {
236
+ fs.unlinkSync(cachePath);
237
+ }
238
+ }
219
239
  function isTokenValid(entry) {
220
240
  const expiresAt = new Date(entry.expiresAt).getTime();
221
241
  return Date.now() + EXPIRY_BUFFER_MS < expiresAt;
@@ -291,17 +311,15 @@ async function resolveCredentialChain(opts) {
291
311
  const configDir = await resolveConfigDir(opts.configDir);
292
312
  const profileName = opts.profile ?? getEnv("SECLAI_PROFILE") ?? "default";
293
313
  const ssoProfile = await loadSsoProfile(configDir, profileName);
294
- if (ssoProfile) {
295
- return {
296
- mode: "sso",
297
- apiKeyHeader,
298
- accountId: opts.accountId ?? ssoProfile.ssoAccountId,
299
- ssoProfile,
300
- configDir,
301
- autoRefresh: opts.autoRefresh !== false,
302
- fetcher: opts.fetch
303
- };
304
- }
314
+ return {
315
+ mode: "sso",
316
+ apiKeyHeader,
317
+ accountId: opts.accountId ?? ssoProfile.ssoAccountId,
318
+ ssoProfile,
319
+ configDir,
320
+ autoRefresh: opts.autoRefresh !== false,
321
+ fetcher: opts.fetch
322
+ };
305
323
  } catch {
306
324
  }
307
325
  throw new Error(
@@ -371,7 +389,9 @@ function getEnv2(name) {
371
389
  return p?.env?.[name];
372
390
  }
373
391
  function buildURL(baseUrl, path, query) {
374
- const url = new URL(path, baseUrl);
392
+ const base = baseUrl.endsWith("/") ? baseUrl : `${baseUrl}/`;
393
+ const relative = path.startsWith("/") ? path.slice(1) : path;
394
+ const url = new URL(relative, base);
375
395
  if (query) {
376
396
  for (const [key, value] of Object.entries(query)) {
377
397
  if (value === void 0 || value === null) continue;
@@ -777,6 +797,21 @@ var Seclai = class {
777
797
  await this.request("DELETE", `/agents/${agentId}`);
778
798
  }
779
799
  // ═══════════════════════════════════════════════════════════════════════════
800
+ // Agent Export
801
+ // ═══════════════════════════════════════════════════════════════════════════
802
+ /**
803
+ * Export an agent definition as a portable JSON snapshot.
804
+ *
805
+ * @param agentId - Agent identifier.
806
+ * @param download - When true (default), the server sets Content-Disposition: attachment.
807
+ * @returns The exported agent snapshot.
808
+ */
809
+ async exportAgent(agentId, download = true) {
810
+ return await this.request("GET", `/agents/${agentId}/export`, {
811
+ query: { download }
812
+ });
813
+ }
814
+ // ═══════════════════════════════════════════════════════════════════════════
780
815
  // Agent Definitions
781
816
  // ═══════════════════════════════════════════════════════════════════════════
782
817
  /**
@@ -2273,12 +2308,20 @@ var Seclai = class {
2273
2308
  };
2274
2309
  // Annotate the CommonJS export names for ESM import in node:
2275
2310
  0 && (module.exports = {
2311
+ DEFAULT_SSO_CLIENT_ID,
2312
+ DEFAULT_SSO_DOMAIN,
2313
+ DEFAULT_SSO_REGION,
2276
2314
  SECLAI_API_URL,
2277
2315
  Seclai,
2278
2316
  SeclaiAPIStatusError,
2279
2317
  SeclaiAPIValidationError,
2280
2318
  SeclaiConfigurationError,
2281
2319
  SeclaiError,
2282
- SeclaiStreamingError
2320
+ SeclaiStreamingError,
2321
+ deleteSsoCache,
2322
+ isTokenValid,
2323
+ loadSsoProfile,
2324
+ readSsoCache,
2325
+ writeSsoCache
2283
2326
  });
2284
2327
  //# sourceMappingURL=index.cjs.map