@graph8/sdk 0.11.0 → 0.12.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -1703,14 +1703,20 @@ var createIntentClient = (apiKey, apiUrl) => {
1703
1703
  /**
1704
1704
  * Find companies whose users visited a specific URL (intent search).
1705
1705
  *
1706
- * Note: this endpoint lives at the bare host (no `/api/v1` prefix), unlike the rest
1707
- * of the intent surface we call it directly here instead of through the shared `post()` helper.
1706
+ * Previously posted to the bare-host `/intent-search/url-companies`, bypassing
1707
+ * the shared `post()` helper. That route is JWT-only, so this method could
1708
+ * never actually work with an API key. It now goes through
1709
+ * `/api/v1/intent/url-companies` like the rest of the intent surface (g8 issue
1710
+ * #16536).
1711
+ *
1712
+ * Returns a bare aggregate, NOT the `{ data }` envelope — the previous
1713
+ * `{ data: IntentCompany[] }` signature never matched what the API sends.
1714
+ *
1715
+ * `date_from` / `date_to` are accepted for backwards compatibility but have
1716
+ * never been read by this endpoint; use `days` to set the lookback window.
1708
1717
  */
1709
1718
  async urlCompanies(url, params = {}) {
1710
- return request(baseUrl, "/intent-search/url-companies", apiKey, {
1711
- method: "POST",
1712
- body: { url, ...params }
1713
- });
1719
+ return post("/intent/url-companies", { url, ...params });
1714
1720
  }
1715
1721
  };
1716
1722
  };
@@ -2267,12 +2273,181 @@ var G8 = class {
2267
2273
  }
2268
2274
  };
2269
2275
  var g8 = new G8();
2276
+
2277
+ // src/appTokens.ts
2278
+ var DEFAULT_APP_API = "https://be.graph8.com";
2279
+ function createTokenManager(args) {
2280
+ const now = args.now ?? (() => Date.now());
2281
+ const skewMs = args.refreshSkewMs ?? 6e4;
2282
+ let token = null;
2283
+ let expiresAtMs = 0;
2284
+ let inflight = null;
2285
+ const doRefresh = async () => {
2286
+ const resp = await args.refresh();
2287
+ token = resp.access_token;
2288
+ expiresAtMs = now() + Math.max(0, resp.expires_in) * 1e3;
2289
+ return token;
2290
+ };
2291
+ return {
2292
+ async getToken(force = false) {
2293
+ const stillFresh = !force && token !== null && now() < expiresAtMs - skewMs;
2294
+ if (stillFresh) return token;
2295
+ if (!inflight) {
2296
+ inflight = doRefresh().finally(() => {
2297
+ inflight = null;
2298
+ });
2299
+ }
2300
+ return inflight;
2301
+ },
2302
+ expiresAt() {
2303
+ return expiresAtMs;
2304
+ }
2305
+ };
2306
+ }
2307
+ function createAppRequester(args) {
2308
+ const { baseUrl, tokens, extraHeaders, fetchImpl, sleepImpl } = args;
2309
+ const appRequest = async (path, opts = {}) => {
2310
+ const headers = { ...extraHeaders ?? {}, ...opts.headers ?? {} };
2311
+ const reqOpts = { ...opts, headers, fetchImpl, sleepImpl };
2312
+ const token = await tokens.getToken();
2313
+ try {
2314
+ return await request(baseUrl, path, token, reqOpts);
2315
+ } catch (err) {
2316
+ if (err instanceof G8Error && err.status === 401) {
2317
+ const fresh = await tokens.getToken(true);
2318
+ return await request(baseUrl, path, fresh, reqOpts);
2319
+ }
2320
+ throw err;
2321
+ }
2322
+ };
2323
+ return appRequest;
2324
+ }
2325
+ async function exchangeBrowserToken(args) {
2326
+ const propelToken = await Promise.resolve(args.getPropelAuthToken());
2327
+ if (!propelToken) {
2328
+ throw new G8Error({
2329
+ message: "getPropelAuthToken() returned no token \u2014 cannot exchange a browser app session",
2330
+ status: 401,
2331
+ type: "app_token_invalid",
2332
+ code: "app_token_invalid"
2333
+ });
2334
+ }
2335
+ const resp = await request(
2336
+ args.baseUrl,
2337
+ "/api/v1/app-sessions/exchange",
2338
+ propelToken,
2339
+ {
2340
+ method: "POST",
2341
+ body: { app_id: args.appId, scopes: args.scopes ?? [] },
2342
+ fetchImpl: args.fetchImpl,
2343
+ sleepImpl: args.sleepImpl
2344
+ }
2345
+ );
2346
+ return resp.data ?? resp;
2347
+ }
2348
+ async function exchangeServiceToken(args) {
2349
+ const resp = await request(
2350
+ args.baseUrl,
2351
+ "/api/v1/service-token",
2352
+ "",
2353
+ {
2354
+ method: "POST",
2355
+ body: {
2356
+ client_id: args.clientId,
2357
+ client_secret: args.clientSecret,
2358
+ scopes: args.scopes ?? [],
2359
+ ttl_seconds: args.ttlSeconds ?? null
2360
+ },
2361
+ fetchImpl: args.fetchImpl,
2362
+ sleepImpl: args.sleepImpl
2363
+ }
2364
+ );
2365
+ return resp.data ?? resp;
2366
+ }
2367
+
2368
+ // src/appClient.ts
2369
+ function createGraph8AppClient(config) {
2370
+ if (typeof config?.getPropelAuthToken !== "function") {
2371
+ throw new Error(
2372
+ "createGraph8AppClient requires getPropelAuthToken() \u2014 a function returning the caller's PropelAuth token"
2373
+ );
2374
+ }
2375
+ const asRecord = config;
2376
+ if ("apiKey" in asRecord || "writeKey" in asRecord) {
2377
+ throw new Error(
2378
+ "createGraph8AppClient does not accept an org API key or write key in the browser \u2014 pass getPropelAuthToken() instead"
2379
+ );
2380
+ }
2381
+ const baseUrl = config.apiUrl || DEFAULT_APP_API;
2382
+ const tokens = createTokenManager({
2383
+ now: config.now,
2384
+ refreshSkewMs: config.refreshSkewMs,
2385
+ refresh: () => exchangeBrowserToken({
2386
+ baseUrl,
2387
+ appId: config.appId,
2388
+ scopes: config.scopes,
2389
+ getPropelAuthToken: config.getPropelAuthToken,
2390
+ fetchImpl: config.fetchImpl,
2391
+ sleepImpl: config.sleepImpl
2392
+ })
2393
+ });
2394
+ const req = createAppRequester({ baseUrl, tokens, fetchImpl: config.fetchImpl, sleepImpl: config.sleepImpl });
2395
+ return {
2396
+ appId: config.appId,
2397
+ tenantOrgId: config.tenantOrgId,
2398
+ request: req,
2399
+ getAppToken: (force = false) => tokens.getToken(force)
2400
+ };
2401
+ }
2402
+ function createGraph8ServiceClient(config) {
2403
+ if (!config?.clientId || !config?.clientSecret) {
2404
+ throw new Error("createGraph8ServiceClient requires clientId and clientSecret");
2405
+ }
2406
+ if (!config?.tenantOrgId) {
2407
+ throw new Error(
2408
+ "createGraph8ServiceClient requires tenantOrgId \u2014 the single consented client org this backend acts for"
2409
+ );
2410
+ }
2411
+ const baseUrl = config.apiUrl || DEFAULT_APP_API;
2412
+ const tokens = createTokenManager({
2413
+ now: config.now,
2414
+ refreshSkewMs: config.refreshSkewMs,
2415
+ refresh: () => exchangeServiceToken({
2416
+ baseUrl,
2417
+ clientId: config.clientId,
2418
+ clientSecret: config.clientSecret,
2419
+ scopes: config.scopes,
2420
+ ttlSeconds: config.ttlSeconds,
2421
+ fetchImpl: config.fetchImpl,
2422
+ sleepImpl: config.sleepImpl
2423
+ })
2424
+ });
2425
+ const req = createAppRequester({
2426
+ baseUrl,
2427
+ tokens,
2428
+ extraHeaders: { "X-Target-Org-Id": config.tenantOrgId },
2429
+ fetchImpl: config.fetchImpl,
2430
+ sleepImpl: config.sleepImpl
2431
+ });
2432
+ return {
2433
+ tenantOrgId: config.tenantOrgId,
2434
+ request: req,
2435
+ getServiceToken: (force = false) => tokens.getToken(force)
2436
+ };
2437
+ }
2270
2438
  export {
2439
+ DEFAULT_APP_API,
2271
2440
  G8Error,
2272
2441
  KNOWN_WEBHOOK_EVENTS,
2273
2442
  WebhookSignatureError,
2274
2443
  backoffDelayMs,
2275
2444
  constructEvent,
2445
+ createAppRequester,
2446
+ createGraph8AppClient,
2447
+ createGraph8ServiceClient,
2448
+ createTokenManager,
2449
+ exchangeBrowserToken,
2450
+ exchangeServiceToken,
2276
2451
  g8,
2277
2452
  isRetryableStatus,
2278
2453
  paginate,