@sailpoint/connector-sdk 1.1.41 → 1.2.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.
@@ -0,0 +1,90 @@
1
+ /**
2
+ * Key prefix reserved for internal SDK use. User keys must not start with this prefix.
3
+ */
4
+ export declare const SDK_CACHE_PREFIX = "__sdk:";
5
+ /**
6
+ * A general-purpose in-memory cache with TTL support.
7
+ *
8
+ * Because connectors run in a Lambda-like environment where module-level state persists
9
+ * across warm invocations, values stored in the cache remain available between requests
10
+ * as long as the container stays warm.
11
+ *
12
+ * The SDK uses this cache internally for auth token storage (with reserved keys prefixed
13
+ * by `__sdk:`). Connector developers can use it to cache any data that is expensive to
14
+ * fetch on every invocation.
15
+ *
16
+ * @example
17
+ * ```typescript
18
+ * import { connectorCache } from '@sailpoint/connector-sdk'
19
+ *
20
+ * // Cache an API response for 5 minutes using fetch()
21
+ * const users = await connectorCache.fetch('all-users', () => myClient.getUsers(), 300)
22
+ * ```
23
+ */
24
+ export declare class ConnectorCache {
25
+ private readonly store;
26
+ private readonly inflight;
27
+ /**
28
+ * Get a value from the cache. Returns `undefined` if the key does not exist or has expired.
29
+ * @param key Cache key
30
+ */
31
+ get<T = any>(key: string): T | undefined;
32
+ /**
33
+ * Store a value in the cache.
34
+ * @param key Cache key (must not start with `__sdk:` — that prefix is reserved for internal use)
35
+ * @param value Value to cache
36
+ * @param ttlSeconds Time-to-live in seconds. If omitted, the entry never expires.
37
+ */
38
+ set<T = any>(key: string, value: T, ttlSeconds?: number): void;
39
+ /**
40
+ * Check whether a key exists and has not expired.
41
+ * @param key Cache key
42
+ */
43
+ has(key: string): boolean;
44
+ /**
45
+ * Return the cached value for `key`, or compute and store it if absent.
46
+ *
47
+ * If the key is not in the cache (or has expired), `factory` is called once to produce
48
+ * the value, which is then stored with the given TTL. Concurrent calls with the same key
49
+ * are deduplicated — only one `factory` invocation runs, and all callers receive the
50
+ * same result.
51
+ *
52
+ * @param key Cache key
53
+ * @param factory Async function that produces the value when the cache is empty
54
+ * @param ttlSeconds Time-to-live in seconds. If omitted, the entry never expires.
55
+ *
56
+ * @example
57
+ * ```typescript
58
+ * const entitlementMap = await connectorCache.fetch(
59
+ * 'entitlement-map',
60
+ * async () => {
61
+ * const entitlements = await client.listEntitlements()
62
+ * return new Map(entitlements.map(e => [e.id, e.name]))
63
+ * },
64
+ * 600,
65
+ * )
66
+ * ```
67
+ */
68
+ fetch<T = any>(key: string, factory: () => Promise<T>, ttlSeconds?: number): Promise<T>;
69
+ /**
70
+ * Remove a key from the cache.
71
+ * @param key Cache key
72
+ */
73
+ delete(key: string): boolean;
74
+ /**
75
+ * Remove all entries from the cache. By default, only clears user entries and
76
+ * preserves internal SDK entries. Pass `true` to clear everything.
77
+ * @param includeInternal If true, also clears internal SDK cache entries
78
+ */
79
+ clear(includeInternal?: boolean): void;
80
+ /**
81
+ * Get the number of entries currently in the cache (including expired but not yet evicted).
82
+ */
83
+ get size(): number;
84
+ private validateUserKey;
85
+ }
86
+ /**
87
+ * Module-level singleton cache instance. Persists across warm invocations in Lambda-like environments.
88
+ */
89
+ export declare const connectorCache: ConnectorCache;
90
+ //# sourceMappingURL=cache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../../lib/cache.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,eAAO,MAAM,gBAAgB,WAAW,CAAA;AAOxC;;;;;;;;;;;;;;;;;;GAkBG;AACH,qBAAa,cAAc;IAC1B,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAqC;IAC3D,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAkC;IAE3D;;;OAGG;IACH,GAAG,CAAC,CAAC,GAAG,GAAG,EAAE,GAAG,EAAE,MAAM,GAAG,CAAC,GAAG,SAAS;IAYxC;;;;;OAKG;IACH,GAAG,CAAC,CAAC,GAAG,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI;IAQ9D;;;OAGG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAIzB;;;;;;;;;;;;;;;;;;;;;;;OAuBG;IACG,KAAK,CAAC,CAAC,GAAG,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC;IAwB7F;;;OAGG;IACH,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAI5B;;;;OAIG;IACH,KAAK,CAAC,eAAe,GAAE,OAAe,GAAG,IAAI;IAY7C;;OAEG;IACH,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED,OAAO,CAAC,eAAe;CAKvB;AAED;;GAEG;AACH,eAAO,MAAM,cAAc,gBAAuB,CAAA"}
@@ -0,0 +1,152 @@
1
+ "use strict";
2
+ /* Copyright (c) 2021. SailPoint Technologies, Inc. All rights reserved. */
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.connectorCache = exports.ConnectorCache = exports.SDK_CACHE_PREFIX = void 0;
5
+ /**
6
+ * Key prefix reserved for internal SDK use. User keys must not start with this prefix.
7
+ */
8
+ exports.SDK_CACHE_PREFIX = '__sdk:';
9
+ /**
10
+ * A general-purpose in-memory cache with TTL support.
11
+ *
12
+ * Because connectors run in a Lambda-like environment where module-level state persists
13
+ * across warm invocations, values stored in the cache remain available between requests
14
+ * as long as the container stays warm.
15
+ *
16
+ * The SDK uses this cache internally for auth token storage (with reserved keys prefixed
17
+ * by `__sdk:`). Connector developers can use it to cache any data that is expensive to
18
+ * fetch on every invocation.
19
+ *
20
+ * @example
21
+ * ```typescript
22
+ * import { connectorCache } from '@sailpoint/connector-sdk'
23
+ *
24
+ * // Cache an API response for 5 minutes using fetch()
25
+ * const users = await connectorCache.fetch('all-users', () => myClient.getUsers(), 300)
26
+ * ```
27
+ */
28
+ class ConnectorCache {
29
+ constructor() {
30
+ this.store = new Map();
31
+ this.inflight = new Map();
32
+ }
33
+ /**
34
+ * Get a value from the cache. Returns `undefined` if the key does not exist or has expired.
35
+ * @param key Cache key
36
+ */
37
+ get(key) {
38
+ const entry = this.store.get(key);
39
+ if (!entry) {
40
+ return undefined;
41
+ }
42
+ if (entry.expiresAt !== null && Date.now() >= entry.expiresAt) {
43
+ this.store.delete(key);
44
+ return undefined;
45
+ }
46
+ return entry.value;
47
+ }
48
+ /**
49
+ * Store a value in the cache.
50
+ * @param key Cache key (must not start with `__sdk:` — that prefix is reserved for internal use)
51
+ * @param value Value to cache
52
+ * @param ttlSeconds Time-to-live in seconds. If omitted, the entry never expires.
53
+ */
54
+ set(key, value, ttlSeconds) {
55
+ if (!key.startsWith(exports.SDK_CACHE_PREFIX)) {
56
+ this.validateUserKey(key);
57
+ }
58
+ const expiresAt = ttlSeconds != null ? Date.now() + ttlSeconds * 1000 : null;
59
+ this.store.set(key, { value, expiresAt });
60
+ }
61
+ /**
62
+ * Check whether a key exists and has not expired.
63
+ * @param key Cache key
64
+ */
65
+ has(key) {
66
+ return this.get(key) !== undefined;
67
+ }
68
+ /**
69
+ * Return the cached value for `key`, or compute and store it if absent.
70
+ *
71
+ * If the key is not in the cache (or has expired), `factory` is called once to produce
72
+ * the value, which is then stored with the given TTL. Concurrent calls with the same key
73
+ * are deduplicated — only one `factory` invocation runs, and all callers receive the
74
+ * same result.
75
+ *
76
+ * @param key Cache key
77
+ * @param factory Async function that produces the value when the cache is empty
78
+ * @param ttlSeconds Time-to-live in seconds. If omitted, the entry never expires.
79
+ *
80
+ * @example
81
+ * ```typescript
82
+ * const entitlementMap = await connectorCache.fetch(
83
+ * 'entitlement-map',
84
+ * async () => {
85
+ * const entitlements = await client.listEntitlements()
86
+ * return new Map(entitlements.map(e => [e.id, e.name]))
87
+ * },
88
+ * 600,
89
+ * )
90
+ * ```
91
+ */
92
+ async fetch(key, factory, ttlSeconds) {
93
+ const cached = this.get(key);
94
+ if (cached !== undefined) {
95
+ return cached;
96
+ }
97
+ const existing = this.inflight.get(key);
98
+ if (existing) {
99
+ return existing;
100
+ }
101
+ const promise = factory().then((value) => {
102
+ this.set(key, value, ttlSeconds);
103
+ this.inflight.delete(key);
104
+ return value;
105
+ }).catch((err) => {
106
+ this.inflight.delete(key);
107
+ throw err;
108
+ });
109
+ this.inflight.set(key, promise);
110
+ return promise;
111
+ }
112
+ /**
113
+ * Remove a key from the cache.
114
+ * @param key Cache key
115
+ */
116
+ delete(key) {
117
+ return this.store.delete(key);
118
+ }
119
+ /**
120
+ * Remove all entries from the cache. By default, only clears user entries and
121
+ * preserves internal SDK entries. Pass `true` to clear everything.
122
+ * @param includeInternal If true, also clears internal SDK cache entries
123
+ */
124
+ clear(includeInternal = false) {
125
+ if (includeInternal) {
126
+ this.store.clear();
127
+ return;
128
+ }
129
+ for (const key of Array.from(this.store.keys())) {
130
+ if (!key.startsWith(exports.SDK_CACHE_PREFIX)) {
131
+ this.store.delete(key);
132
+ }
133
+ }
134
+ }
135
+ /**
136
+ * Get the number of entries currently in the cache (including expired but not yet evicted).
137
+ */
138
+ get size() {
139
+ return this.store.size;
140
+ }
141
+ validateUserKey(key) {
142
+ if (key.startsWith(exports.SDK_CACHE_PREFIX)) {
143
+ throw new Error(`Cache keys starting with "${exports.SDK_CACHE_PREFIX}" are reserved for internal SDK use`);
144
+ }
145
+ }
146
+ }
147
+ exports.ConnectorCache = ConnectorCache;
148
+ /**
149
+ * Module-level singleton cache instance. Persists across warm invocations in Lambda-like environments.
150
+ */
151
+ exports.connectorCache = new ConnectorCache();
152
+ //# sourceMappingURL=cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.js","sourceRoot":"","sources":["../../lib/cache.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,102 @@
1
+ import { Response } from './response';
2
+ import { Context } from './connector-handler';
3
+ /**
4
+ * A persistent key-value data store backed by source config attributes.
5
+ *
6
+ * Provides a simple API to read and write values that persist across connector invocations.
7
+ * Under the hood, changes are sent via `patchConfig` as JSON Patch operations targeting
8
+ * `/<key>` directly. Only changed values are patched — if a value is set to the same thing
9
+ * it was before, no patch is emitted.
10
+ *
11
+ * During long aggregations, call `reload(context)` to pick up config changes that occurred
12
+ * mid-run (including values written by a previous `flush()` call in the same invocation).
13
+ *
14
+ * @example
15
+ * ```typescript
16
+ * import { createConnectorDataStore, readConfig } from '@sailpoint/connector-sdk'
17
+ *
18
+ * // Inside a command handler:
19
+ * async (context, input, res) => {
20
+ * const config = await readConfig()
21
+ * const dataStore = createConnectorDataStore(config, res)
22
+ *
23
+ * // Read a previously stored value
24
+ * const lastSync = dataStore.get<string>('lastSyncTimestamp')
25
+ *
26
+ * // Fetch data since last sync...
27
+ * const data = await fetchDataSince(lastSync)
28
+ *
29
+ * // Store the new timestamp (only patched if different)
30
+ * dataStore.set('lastSyncTimestamp', new Date().toISOString())
31
+ *
32
+ * // Send all accumulated changes
33
+ * dataStore.flush()
34
+ * }
35
+ * ```
36
+ */
37
+ export declare class ConnectorDataStore {
38
+ private config;
39
+ private readonly res;
40
+ private readonly pending;
41
+ constructor(config: Record<string, any>, res: Response<any>);
42
+ /**
43
+ * Get a value from the config.
44
+ * Returns the pending value if one has been set, otherwise the original config value.
45
+ * @param key Attribute key
46
+ */
47
+ get<T = any>(key: string): T | undefined;
48
+ /**
49
+ * Set a value in the config. The change is buffered until `flush()` is called.
50
+ * If the value is identical to the current stored value, no patch will be emitted.
51
+ * @param key Attribute key
52
+ * @param value Value to store (must be JSON-serializable)
53
+ */
54
+ set(key: string, value: any): void;
55
+ /**
56
+ * Remove a key from the config. The change is buffered until `flush()` is called.
57
+ * If the key doesn't exist, no patch will be emitted.
58
+ * @param key Attribute key to remove
59
+ */
60
+ delete(key: string): void;
61
+ /**
62
+ * Returns true if there are pending changes that haven't been flushed yet.
63
+ */
64
+ get hasPendingChanges(): boolean;
65
+ /**
66
+ * Send all accumulated changes as a single `patchConfig` call.
67
+ * Only emits patches for values that differ from the current config.
68
+ * After flushing, the local config is updated to reflect the sent patches so that
69
+ * subsequent `set()` calls in the same invocation use the correct baseline for
70
+ * change detection.
71
+ */
72
+ flush(): void;
73
+ /**
74
+ * Reload the connector config from ISC via the command context and update the data
75
+ * store's baseline. Call this during long aggregations to pick up config changes that
76
+ * occurred mid-run — for example, values written by a previous `flush()` call or
77
+ * updates made externally.
78
+ *
79
+ * Pending changes are preserved across a reload.
80
+ *
81
+ * @param context The command context passed to the handler
82
+ *
83
+ * @example
84
+ * ```typescript
85
+ * // Flush a batch of changes, then reload so the next batch uses the updated baseline
86
+ * dataStore.set('cursor', nextCursor)
87
+ * dataStore.flush()
88
+ * await dataStore.reload(context)
89
+ * ```
90
+ */
91
+ reload(context: Context): Promise<void>;
92
+ private deepEqual;
93
+ }
94
+ /**
95
+ * Creates a persistent data store backed by source config attributes.
96
+ *
97
+ * @param config The connector config object (from `readConfig()`)
98
+ * @param res The response object from the current command handler
99
+ * @returns A ConnectorDataStore instance
100
+ */
101
+ export declare function createConnectorDataStore(config: Record<string, any>, res: Response<any>): ConnectorDataStore;
102
+ //# sourceMappingURL=data-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"data-store.d.ts","sourceRoot":"","sources":["../../lib/data-store.ts"],"names":[],"mappings":"AAEA,OAAO,EAAkB,QAAQ,EAAE,MAAM,YAAY,CAAA;AACrD,OAAO,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAG7C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,qBAAa,kBAAkB;IAC9B,OAAO,CAAC,MAAM,CAAqB;IACnC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAe;IACnC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA2D;gBAEvE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,GAAG,EAAE,QAAQ,CAAC,GAAG,CAAC;IAK3D;;;;OAIG;IACH,GAAG,CAAC,CAAC,GAAG,GAAG,EAAE,GAAG,EAAE,MAAM,GAAG,CAAC,GAAG,SAAS;IAQxC;;;;;OAKG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,GAAG,IAAI;IASlC;;;;OAIG;IACH,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAQzB;;OAEG;IACH,IAAI,iBAAiB,IAAI,OAAO,CAE/B;IAED;;;;;;OAMG;IACH,KAAK,IAAI,IAAI;IAyCb;;;;;;;;;;;;;;;;;OAiBG;IACG,MAAM,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAI7C,OAAO,CAAC,SAAS;CAOjB;AAED;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,GAAG,EAAE,QAAQ,CAAC,GAAG,CAAC,GAAG,kBAAkB,CAE5G"}
@@ -0,0 +1,178 @@
1
+ "use strict";
2
+ /* Copyright (c) 2021. SailPoint Technologies, Inc. All rights reserved. */
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.createConnectorDataStore = exports.ConnectorDataStore = void 0;
5
+ const response_1 = require("./response");
6
+ const logger_1 = require("./logger");
7
+ /**
8
+ * A persistent key-value data store backed by source config attributes.
9
+ *
10
+ * Provides a simple API to read and write values that persist across connector invocations.
11
+ * Under the hood, changes are sent via `patchConfig` as JSON Patch operations targeting
12
+ * `/<key>` directly. Only changed values are patched — if a value is set to the same thing
13
+ * it was before, no patch is emitted.
14
+ *
15
+ * During long aggregations, call `reload(context)` to pick up config changes that occurred
16
+ * mid-run (including values written by a previous `flush()` call in the same invocation).
17
+ *
18
+ * @example
19
+ * ```typescript
20
+ * import { createConnectorDataStore, readConfig } from '@sailpoint/connector-sdk'
21
+ *
22
+ * // Inside a command handler:
23
+ * async (context, input, res) => {
24
+ * const config = await readConfig()
25
+ * const dataStore = createConnectorDataStore(config, res)
26
+ *
27
+ * // Read a previously stored value
28
+ * const lastSync = dataStore.get<string>('lastSyncTimestamp')
29
+ *
30
+ * // Fetch data since last sync...
31
+ * const data = await fetchDataSince(lastSync)
32
+ *
33
+ * // Store the new timestamp (only patched if different)
34
+ * dataStore.set('lastSyncTimestamp', new Date().toISOString())
35
+ *
36
+ * // Send all accumulated changes
37
+ * dataStore.flush()
38
+ * }
39
+ * ```
40
+ */
41
+ class ConnectorDataStore {
42
+ constructor(config, res) {
43
+ this.pending = new Map();
44
+ this.config = config;
45
+ this.res = res;
46
+ }
47
+ /**
48
+ * Get a value from the config.
49
+ * Returns the pending value if one has been set, otherwise the original config value.
50
+ * @param key Attribute key
51
+ */
52
+ get(key) {
53
+ const pendingEntry = this.pending.get(key);
54
+ if (pendingEntry) {
55
+ return pendingEntry.op === 'delete' ? undefined : pendingEntry.value;
56
+ }
57
+ return this.config?.[key];
58
+ }
59
+ /**
60
+ * Set a value in the config. The change is buffered until `flush()` is called.
61
+ * If the value is identical to the current stored value, no patch will be emitted.
62
+ * @param key Attribute key
63
+ * @param value Value to store (must be JSON-serializable)
64
+ */
65
+ set(key, value) {
66
+ const current = this.config?.[key];
67
+ if (this.deepEqual(current, value)) {
68
+ this.pending.delete(key);
69
+ return;
70
+ }
71
+ this.pending.set(key, { op: 'set', value });
72
+ }
73
+ /**
74
+ * Remove a key from the config. The change is buffered until `flush()` is called.
75
+ * If the key doesn't exist, no patch will be emitted.
76
+ * @param key Attribute key to remove
77
+ */
78
+ delete(key) {
79
+ const exists = this.config?.hasOwnProperty(key);
80
+ if (!exists && !this.pending.has(key)) {
81
+ return;
82
+ }
83
+ this.pending.set(key, { op: 'delete' });
84
+ }
85
+ /**
86
+ * Returns true if there are pending changes that haven't been flushed yet.
87
+ */
88
+ get hasPendingChanges() {
89
+ return this.pending.size > 0;
90
+ }
91
+ /**
92
+ * Send all accumulated changes as a single `patchConfig` call.
93
+ * Only emits patches for values that differ from the current config.
94
+ * After flushing, the local config is updated to reflect the sent patches so that
95
+ * subsequent `set()` calls in the same invocation use the correct baseline for
96
+ * change detection.
97
+ */
98
+ flush() {
99
+ if (this.pending.size === 0) {
100
+ return;
101
+ }
102
+ const log = logger_1.logger.child({ component: 'data-store' });
103
+ log.debug({ config: this.config ?? null }, 'data-store flush: config baseline');
104
+ const patches = [];
105
+ for (const [key, entry] of this.pending) {
106
+ if (entry.op === 'delete') {
107
+ patches.push({ op: response_1.PatchOp.Remove, path: `/${key}` });
108
+ }
109
+ else {
110
+ const existed = this.config?.hasOwnProperty(key);
111
+ patches.push({
112
+ op: existed ? response_1.PatchOp.Replace : response_1.PatchOp.Add,
113
+ path: `/${key}`,
114
+ value: entry.value,
115
+ });
116
+ }
117
+ }
118
+ log.debug({ patches }, 'data-store flush: sending patches');
119
+ if (patches.length > 0) {
120
+ this.res.patchConfig(patches);
121
+ }
122
+ // Update the local config baseline so subsequent set() calls detect no change
123
+ for (const [key, entry] of this.pending) {
124
+ if (entry.op === 'delete') {
125
+ delete this.config[key];
126
+ }
127
+ else {
128
+ this.config[key] = entry.value;
129
+ }
130
+ }
131
+ this.pending.clear();
132
+ }
133
+ /**
134
+ * Reload the connector config from ISC via the command context and update the data
135
+ * store's baseline. Call this during long aggregations to pick up config changes that
136
+ * occurred mid-run — for example, values written by a previous `flush()` call or
137
+ * updates made externally.
138
+ *
139
+ * Pending changes are preserved across a reload.
140
+ *
141
+ * @param context The command context passed to the handler
142
+ *
143
+ * @example
144
+ * ```typescript
145
+ * // Flush a batch of changes, then reload so the next batch uses the updated baseline
146
+ * dataStore.set('cursor', nextCursor)
147
+ * dataStore.flush()
148
+ * await dataStore.reload(context)
149
+ * ```
150
+ */
151
+ async reload(context) {
152
+ this.config = await context.reloadConfig();
153
+ }
154
+ deepEqual(a, b) {
155
+ if (a === b)
156
+ return true;
157
+ if (a == null || b == null)
158
+ return false;
159
+ if (typeof a !== typeof b)
160
+ return false;
161
+ if (typeof a !== 'object')
162
+ return false;
163
+ return JSON.stringify(a) === JSON.stringify(b);
164
+ }
165
+ }
166
+ exports.ConnectorDataStore = ConnectorDataStore;
167
+ /**
168
+ * Creates a persistent data store backed by source config attributes.
169
+ *
170
+ * @param config The connector config object (from `readConfig()`)
171
+ * @param res The response object from the current command handler
172
+ * @returns A ConnectorDataStore instance
173
+ */
174
+ function createConnectorDataStore(config, res) {
175
+ return new ConnectorDataStore(config, res);
176
+ }
177
+ exports.createConnectorDataStore = createConnectorDataStore;
178
+ //# sourceMappingURL=data-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"data-store.js","sourceRoot":"","sources":["../../lib/data-store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,195 @@
1
+ import { AxiosInstance, CreateAxiosDefaults } from 'axios';
2
+ export type { AxiosInstance } from 'axios';
3
+ /**
4
+ * Basic authentication using username and password
5
+ */
6
+ export interface BasicAuth {
7
+ type: 'basic';
8
+ username: string;
9
+ password: string;
10
+ }
11
+ /**
12
+ * Bearer token authentication using a static token
13
+ */
14
+ export interface BearerTokenAuth {
15
+ type: 'bearer';
16
+ token: string;
17
+ }
18
+ /**
19
+ * API key authentication sent as a header or query parameter
20
+ */
21
+ export interface ApiKeyAuth {
22
+ type: 'apiKey';
23
+ /**
24
+ * Where to send the API key: 'header' or 'query'
25
+ */
26
+ in: 'header' | 'query';
27
+ /**
28
+ * Name of the header or query parameter (e.g. 'X-API-Key', 'api_key')
29
+ */
30
+ name: string;
31
+ value: string;
32
+ }
33
+ /**
34
+ * OAuth2 Client Credentials grant. Automatically fetches and refreshes access tokens.
35
+ */
36
+ export interface OAuth2ClientCredentialsAuth {
37
+ type: 'oauth2ClientCredentials';
38
+ /**
39
+ * Token endpoint URL (e.g. 'https://auth.example.com/oauth/token')
40
+ */
41
+ tokenUrl: string;
42
+ clientId: string;
43
+ clientSecret: string;
44
+ /**
45
+ * Optional scopes to request
46
+ */
47
+ scope?: string;
48
+ /**
49
+ * How to send credentials: 'body' (form post) or 'header' (Basic auth header).
50
+ * Defaults to 'body'.
51
+ */
52
+ credentialPlacement?: 'body' | 'header';
53
+ }
54
+ export type AuthConfig = BasicAuth | BearerTokenAuth | ApiKeyAuth | OAuth2ClientCredentialsAuth;
55
+ /**
56
+ * Configuration for automatic request retry with exponential backoff.
57
+ */
58
+ export interface RetryConfig {
59
+ /**
60
+ * Maximum number of retry attempts. Set to 0 to disable retries.
61
+ * Default: 3
62
+ */
63
+ maxRetries?: number;
64
+ /**
65
+ * Base delay in milliseconds for exponential backoff. The actual delay is
66
+ * `baseDelay * 2^(attempt - 1)` plus jitter.
67
+ * Default: 1000
68
+ */
69
+ baseDelay?: number;
70
+ /**
71
+ * Maximum delay in milliseconds between retries.
72
+ * Default: 30000
73
+ */
74
+ maxDelay?: number;
75
+ /**
76
+ * HTTP status codes that should trigger a retry.
77
+ * Default: [429, 500, 502, 503, 504]
78
+ */
79
+ retryableStatusCodes?: number[];
80
+ /**
81
+ * Whether to retry on network errors (no response received).
82
+ * Default: true
83
+ */
84
+ retryOnNetworkError?: boolean;
85
+ }
86
+ /**
87
+ * Options for creating a connector HTTP client
88
+ */
89
+ export interface HttpClientOptions {
90
+ /**
91
+ * Base URL for all requests (e.g. 'https://api.example.com/v1')
92
+ */
93
+ baseURL?: string;
94
+ /**
95
+ * Default headers to include on every request
96
+ */
97
+ headers?: Record<string, string>;
98
+ /**
99
+ * Request timeout in milliseconds (default: 30000)
100
+ */
101
+ timeout?: number;
102
+ /**
103
+ * Authentication configuration. Supports basic, bearer, apiKey, and oauth2ClientCredentials.
104
+ */
105
+ auth?: AuthConfig;
106
+ /**
107
+ * Retry configuration. Enabled by default with 3 retries and exponential backoff.
108
+ * Set to `false` to disable retries entirely.
109
+ */
110
+ retry?: RetryConfig | false;
111
+ /**
112
+ * Additional Axios configuration options
113
+ */
114
+ axiosOptions?: CreateAxiosDefaults;
115
+ }
116
+ /**
117
+ * Parses the Retry-After header value into milliseconds to wait.
118
+ * Supports both seconds (integer) and HTTP-date formats.
119
+ * Returns undefined if the header is missing or unparseable.
120
+ */
121
+ export declare function parseRetryAfter(headerValue: string | undefined | null): number | undefined;
122
+ /**
123
+ * Calculates the delay for a retry attempt using exponential backoff with jitter.
124
+ */
125
+ export declare function calculateRetryDelay(attempt: number, baseDelay: number, maxDelay: number): number;
126
+ /**
127
+ * Creates a pre-configured Axios HTTP client instance for use within connectors.
128
+ *
129
+ * The client includes:
130
+ * - Configurable base URL, headers, and timeout
131
+ * - Built-in authentication (basic, bearer, apiKey, oauth2ClientCredentials)
132
+ * - Automatic retry with exponential backoff (429, 5xx, network errors)
133
+ * - Token caching via the shared `connectorCache` (persists across warm invocations)
134
+ * - Request/response logging via the SDK's pino logger
135
+ * - Error logging for failed requests
136
+ *
137
+ * @example Basic auth
138
+ * ```typescript
139
+ * const httpClient = createConnectorHttpClient({
140
+ * baseURL: config.apiUrl,
141
+ * auth: { type: 'basic', username: config.username, password: config.password },
142
+ * })
143
+ * ```
144
+ *
145
+ * @example Bearer token
146
+ * ```typescript
147
+ * const httpClient = createConnectorHttpClient({
148
+ * baseURL: config.apiUrl,
149
+ * auth: { type: 'bearer', token: config.token },
150
+ * })
151
+ * ```
152
+ *
153
+ * @example API key
154
+ * ```typescript
155
+ * const httpClient = createConnectorHttpClient({
156
+ * baseURL: config.apiUrl,
157
+ * auth: { type: 'apiKey', in: 'header', name: 'X-API-Key', value: config.apiKey },
158
+ * })
159
+ * ```
160
+ *
161
+ * @example OAuth2 Client Credentials (automatic token management)
162
+ * ```typescript
163
+ * const httpClient = createConnectorHttpClient({
164
+ * baseURL: config.apiUrl,
165
+ * auth: {
166
+ * type: 'oauth2ClientCredentials',
167
+ * tokenUrl: config.tokenUrl,
168
+ * clientId: config.clientId,
169
+ * clientSecret: config.clientSecret,
170
+ * scope: 'read write',
171
+ * },
172
+ * })
173
+ * ```
174
+ *
175
+ * @example Custom retry configuration
176
+ * ```typescript
177
+ * const httpClient = createConnectorHttpClient({
178
+ * baseURL: config.apiUrl,
179
+ * retry: { maxRetries: 5, baseDelay: 2000 },
180
+ * })
181
+ * ```
182
+ *
183
+ * @example Disable retries
184
+ * ```typescript
185
+ * const httpClient = createConnectorHttpClient({
186
+ * baseURL: config.apiUrl,
187
+ * retry: false,
188
+ * })
189
+ * ```
190
+ *
191
+ * @param options Configuration options for the HTTP client
192
+ * @returns A configured Axios instance
193
+ */
194
+ export declare function createConnectorHttpClient(options?: HttpClientOptions): AxiosInstance;
195
+ //# sourceMappingURL=http-client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http-client.d.ts","sourceRoot":"","sources":["../../lib/http-client.ts"],"names":[],"mappings":"AAEA,OAAc,EAAc,aAAa,EAAE,mBAAmB,EAA8B,MAAM,OAAO,CAAA;AAIzG,YAAY,EAAE,aAAa,EAAE,MAAM,OAAO,CAAA;AAW1C;;GAEG;AACH,MAAM,WAAW,SAAS;IACzB,IAAI,EAAE,OAAO,CAAA;IACb,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,EAAE,MAAM,CAAA;CAChB;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC/B,IAAI,EAAE,QAAQ,CAAA;IACd,KAAK,EAAE,MAAM,CAAA;CACb;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IAC1B,IAAI,EAAE,QAAQ,CAAA;IACd;;OAEG;IACH,EAAE,EAAE,QAAQ,GAAG,OAAO,CAAA;IACtB;;OAEG;IACH,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,MAAM,CAAA;CACb;AAED;;GAEG;AACH,MAAM,WAAW,2BAA2B;IAC3C,IAAI,EAAE,yBAAyB,CAAA;IAC/B;;OAEG;IACH,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,EAAE,MAAM,CAAA;IAChB,YAAY,EAAE,MAAM,CAAA;IACpB;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAA;IACd;;;OAGG;IACH,mBAAmB,CAAC,EAAE,MAAM,GAAG,QAAQ,CAAA;CACvC;AAED,MAAM,MAAM,UAAU,GAAG,SAAS,GAAG,eAAe,GAAG,UAAU,GAAG,2BAA2B,CAAA;AAE/F;;GAEG;AACH,MAAM,WAAW,WAAW;IAC3B;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;IAEnB;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;IAElB;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;IAEjB;;;OAGG;IACH,oBAAoB,CAAC,EAAE,MAAM,EAAE,CAAA;IAE/B;;;OAGG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAA;CAC7B;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IACjC;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAA;IAEhB;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAEhC;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAA;IAEhB;;OAEG;IACH,IAAI,CAAC,EAAE,UAAU,CAAA;IAEjB;;;OAGG;IACH,KAAK,CAAC,EAAE,WAAW,GAAG,KAAK,CAAA;IAE3B;;OAEG;IACH,YAAY,CAAC,EAAE,mBAAmB,CAAA;CAClC;AAoFD;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,GAAG,MAAM,GAAG,SAAS,CAmB1F;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAIhG;AAMD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmEG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,GAAE,iBAAsB,GAAG,aAAa,CA6JxF"}
@@ -0,0 +1,312 @@
1
+ "use strict";
2
+ /* Copyright (c) 2021. SailPoint Technologies, Inc. All rights reserved. */
3
+ var __importDefault = (this && this.__importDefault) || function (mod) {
4
+ return (mod && mod.__esModule) ? mod : { "default": mod };
5
+ };
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.createConnectorHttpClient = exports.calculateRetryDelay = exports.parseRetryAfter = void 0;
8
+ const axios_1 = __importDefault(require("axios"));
9
+ const logger_1 = require("./logger");
10
+ const cache_1 = require("./cache");
11
+ /** Cache key prefix for auth tokens */
12
+ const AUTH_CACHE_PREFIX = `${cache_1.SDK_CACHE_PREFIX}auth:`;
13
+ /** Custom config property to track retry count */
14
+ const RETRY_COUNT_KEY = '__retryCount';
15
+ /** Default status codes that trigger a retry */
16
+ const DEFAULT_RETRYABLE_STATUS_CODES = [429, 500, 502, 503, 504];
17
+ /**
18
+ * Builds a deterministic cache key from the auth config so that the same credentials
19
+ * always resolve to the same cached token, even across multiple `createConnectorHttpClient` calls.
20
+ */
21
+ function authCacheKey(auth) {
22
+ switch (auth.type) {
23
+ case 'oauth2ClientCredentials':
24
+ return `${AUTH_CACHE_PREFIX}oauth2:${auth.tokenUrl}:${auth.clientId}`;
25
+ default:
26
+ return `${AUTH_CACHE_PREFIX}${auth.type}`;
27
+ }
28
+ }
29
+ // Tracks in-flight token fetches to deduplicate concurrent requests
30
+ const inflightTokenRequests = new Map();
31
+ /**
32
+ * Fetches an OAuth2 Client Credentials token, using the shared cache and deduplicating
33
+ * concurrent requests.
34
+ */
35
+ async function getOAuth2Token(config, cacheKey, log) {
36
+ // Check the shared cache first
37
+ const cached = cache_1.connectorCache.get(cacheKey);
38
+ if (cached) {
39
+ return cached;
40
+ }
41
+ // Deduplicate concurrent token requests
42
+ const inflight = inflightTokenRequests.get(cacheKey);
43
+ if (inflight) {
44
+ return inflight;
45
+ }
46
+ const promise = fetchOAuth2Token(config, cacheKey, log);
47
+ inflightTokenRequests.set(cacheKey, promise);
48
+ try {
49
+ return await promise;
50
+ }
51
+ finally {
52
+ inflightTokenRequests.delete(cacheKey);
53
+ }
54
+ }
55
+ async function fetchOAuth2Token(config, cacheKey, log) {
56
+ log.debug({ tokenUrl: config.tokenUrl }, 'Fetching OAuth2 access token');
57
+ const params = new URLSearchParams();
58
+ params.append('grant_type', 'client_credentials');
59
+ if (config.scope) {
60
+ params.append('scope', config.scope);
61
+ }
62
+ const headers = {
63
+ 'Content-Type': 'application/x-www-form-urlencoded',
64
+ };
65
+ if (config.credentialPlacement === 'header') {
66
+ const encoded = Buffer.from(`${config.clientId}:${config.clientSecret}`).toString('base64');
67
+ headers['Authorization'] = `Basic ${encoded}`;
68
+ }
69
+ else {
70
+ params.append('client_id', config.clientId);
71
+ params.append('client_secret', config.clientSecret);
72
+ }
73
+ const response = await axios_1.default.post(config.tokenUrl, params.toString(), { headers });
74
+ const { access_token, expires_in } = response.data;
75
+ // Cache with TTL. Use a 30s buffer so the token is refreshed before it actually expires.
76
+ const ttlSeconds = Math.max((expires_in || 3600) - 30, 0);
77
+ cache_1.connectorCache.set(cacheKey, access_token, ttlSeconds);
78
+ log.debug({ expiresIn: expires_in }, 'OAuth2 access token acquired');
79
+ return access_token;
80
+ }
81
+ /**
82
+ * Parses the Retry-After header value into milliseconds to wait.
83
+ * Supports both seconds (integer) and HTTP-date formats.
84
+ * Returns undefined if the header is missing or unparseable.
85
+ */
86
+ function parseRetryAfter(headerValue) {
87
+ if (!headerValue) {
88
+ return undefined;
89
+ }
90
+ // Try parsing as integer seconds
91
+ const seconds = Number(headerValue);
92
+ if (!isNaN(seconds) && seconds >= 0) {
93
+ return seconds * 1000;
94
+ }
95
+ // Try parsing as HTTP-date
96
+ const date = new Date(headerValue);
97
+ if (!isNaN(date.getTime())) {
98
+ const delay = date.getTime() - Date.now();
99
+ return Math.max(delay, 0);
100
+ }
101
+ return undefined;
102
+ }
103
+ exports.parseRetryAfter = parseRetryAfter;
104
+ /**
105
+ * Calculates the delay for a retry attempt using exponential backoff with jitter.
106
+ */
107
+ function calculateRetryDelay(attempt, baseDelay, maxDelay) {
108
+ const exponentialDelay = baseDelay * Math.pow(2, attempt - 1);
109
+ const jitter = Math.random() * baseDelay * 0.5;
110
+ return Math.min(exponentialDelay + jitter, maxDelay);
111
+ }
112
+ exports.calculateRetryDelay = calculateRetryDelay;
113
+ function sleep(ms) {
114
+ return new Promise((resolve) => setTimeout(resolve, ms));
115
+ }
116
+ /**
117
+ * Creates a pre-configured Axios HTTP client instance for use within connectors.
118
+ *
119
+ * The client includes:
120
+ * - Configurable base URL, headers, and timeout
121
+ * - Built-in authentication (basic, bearer, apiKey, oauth2ClientCredentials)
122
+ * - Automatic retry with exponential backoff (429, 5xx, network errors)
123
+ * - Token caching via the shared `connectorCache` (persists across warm invocations)
124
+ * - Request/response logging via the SDK's pino logger
125
+ * - Error logging for failed requests
126
+ *
127
+ * @example Basic auth
128
+ * ```typescript
129
+ * const httpClient = createConnectorHttpClient({
130
+ * baseURL: config.apiUrl,
131
+ * auth: { type: 'basic', username: config.username, password: config.password },
132
+ * })
133
+ * ```
134
+ *
135
+ * @example Bearer token
136
+ * ```typescript
137
+ * const httpClient = createConnectorHttpClient({
138
+ * baseURL: config.apiUrl,
139
+ * auth: { type: 'bearer', token: config.token },
140
+ * })
141
+ * ```
142
+ *
143
+ * @example API key
144
+ * ```typescript
145
+ * const httpClient = createConnectorHttpClient({
146
+ * baseURL: config.apiUrl,
147
+ * auth: { type: 'apiKey', in: 'header', name: 'X-API-Key', value: config.apiKey },
148
+ * })
149
+ * ```
150
+ *
151
+ * @example OAuth2 Client Credentials (automatic token management)
152
+ * ```typescript
153
+ * const httpClient = createConnectorHttpClient({
154
+ * baseURL: config.apiUrl,
155
+ * auth: {
156
+ * type: 'oauth2ClientCredentials',
157
+ * tokenUrl: config.tokenUrl,
158
+ * clientId: config.clientId,
159
+ * clientSecret: config.clientSecret,
160
+ * scope: 'read write',
161
+ * },
162
+ * })
163
+ * ```
164
+ *
165
+ * @example Custom retry configuration
166
+ * ```typescript
167
+ * const httpClient = createConnectorHttpClient({
168
+ * baseURL: config.apiUrl,
169
+ * retry: { maxRetries: 5, baseDelay: 2000 },
170
+ * })
171
+ * ```
172
+ *
173
+ * @example Disable retries
174
+ * ```typescript
175
+ * const httpClient = createConnectorHttpClient({
176
+ * baseURL: config.apiUrl,
177
+ * retry: false,
178
+ * })
179
+ * ```
180
+ *
181
+ * @param options Configuration options for the HTTP client
182
+ * @returns A configured Axios instance
183
+ */
184
+ function createConnectorHttpClient(options = {}) {
185
+ const { baseURL, headers, timeout = 30000, auth, retry, axiosOptions = {} } = options;
186
+ const client = axios_1.default.create({
187
+ ...axiosOptions,
188
+ baseURL,
189
+ timeout,
190
+ headers: {
191
+ ...axiosOptions.headers,
192
+ ...headers,
193
+ },
194
+ });
195
+ const log = logger_1.logger.child({ component: 'http-client' });
196
+ // Set up authentication interceptor
197
+ if (auth) {
198
+ switch (auth.type) {
199
+ case 'basic': {
200
+ const encoded = Buffer.from(`${auth.username}:${auth.password}`).toString('base64');
201
+ client.interceptors.request.use((config) => {
202
+ config.headers.set('Authorization', `Basic ${encoded}`);
203
+ return config;
204
+ });
205
+ break;
206
+ }
207
+ case 'bearer': {
208
+ client.interceptors.request.use((config) => {
209
+ config.headers.set('Authorization', `Bearer ${auth.token}`);
210
+ return config;
211
+ });
212
+ break;
213
+ }
214
+ case 'apiKey': {
215
+ client.interceptors.request.use((config) => {
216
+ if (auth.in === 'header') {
217
+ config.headers.set(auth.name, auth.value);
218
+ }
219
+ else {
220
+ config.params = { ...config.params, [auth.name]: auth.value };
221
+ }
222
+ return config;
223
+ });
224
+ break;
225
+ }
226
+ case 'oauth2ClientCredentials': {
227
+ const cacheKey = authCacheKey(auth);
228
+ client.interceptors.request.use(async (config) => {
229
+ const token = await getOAuth2Token(auth, cacheKey, log);
230
+ config.headers.set('Authorization', `Bearer ${token}`);
231
+ return config;
232
+ });
233
+ break;
234
+ }
235
+ }
236
+ }
237
+ // Logging interceptors
238
+ client.interceptors.request.use((config) => {
239
+ log.debug({ method: config.method?.toUpperCase(), url: config.url, baseURL: config.baseURL }, 'HTTP request');
240
+ return config;
241
+ }, (error) => {
242
+ log.error({ error: error.message }, 'HTTP request error');
243
+ return Promise.reject(error);
244
+ });
245
+ client.interceptors.response.use((response) => {
246
+ log.debug({ method: response.config.method?.toUpperCase(), url: response.config.url, status: response.status }, 'HTTP response');
247
+ return response;
248
+ }, (error) => {
249
+ if (error.response) {
250
+ log.error({
251
+ method: error.config?.method?.toUpperCase(),
252
+ url: error.config?.url,
253
+ status: error.response.status,
254
+ }, 'HTTP response error');
255
+ }
256
+ else {
257
+ log.error({ message: error.message }, 'HTTP request failed');
258
+ }
259
+ return Promise.reject(error);
260
+ });
261
+ // Retry interceptor (added after logging so retries are logged)
262
+ if (retry !== false) {
263
+ const retryConfig = {
264
+ maxRetries: retry?.maxRetries ?? 3,
265
+ baseDelay: retry?.baseDelay ?? 1000,
266
+ maxDelay: retry?.maxDelay ?? 30000,
267
+ retryableStatusCodes: retry?.retryableStatusCodes ?? DEFAULT_RETRYABLE_STATUS_CODES,
268
+ retryOnNetworkError: retry?.retryOnNetworkError ?? true,
269
+ };
270
+ client.interceptors.response.use(undefined, async (error) => {
271
+ const config = error.config;
272
+ if (!config) {
273
+ return Promise.reject(error);
274
+ }
275
+ const retryCount = config[RETRY_COUNT_KEY] || 0;
276
+ if (retryCount >= retryConfig.maxRetries) {
277
+ return Promise.reject(error);
278
+ }
279
+ const status = error.response?.status;
280
+ const isRetryable = status
281
+ ? retryConfig.retryableStatusCodes.includes(status)
282
+ : retryConfig.retryOnNetworkError && !error.response;
283
+ if (!isRetryable) {
284
+ return Promise.reject(error);
285
+ }
286
+ const attempt = retryCount + 1;
287
+ // For 429, prefer Retry-After header
288
+ let delay;
289
+ if (status === 429) {
290
+ const retryAfterHeader = error.response?.headers?.['retry-after'];
291
+ const retryAfterMs = parseRetryAfter(retryAfterHeader);
292
+ delay = retryAfterMs ?? calculateRetryDelay(attempt, retryConfig.baseDelay, retryConfig.maxDelay);
293
+ }
294
+ else {
295
+ delay = calculateRetryDelay(attempt, retryConfig.baseDelay, retryConfig.maxDelay);
296
+ }
297
+ log.info({
298
+ attempt,
299
+ maxRetries: retryConfig.maxRetries,
300
+ status,
301
+ delay: Math.round(delay),
302
+ url: config.url,
303
+ }, 'Retrying request');
304
+ config[RETRY_COUNT_KEY] = attempt;
305
+ await sleep(delay);
306
+ return client.request(config);
307
+ });
308
+ }
309
+ return client;
310
+ }
311
+ exports.createConnectorHttpClient = createConnectorHttpClient;
312
+ //# sourceMappingURL=http-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http-client.js","sourceRoot":"","sources":["../../lib/http-client.ts"],"names":[],"mappings":"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"}
@@ -10,4 +10,7 @@ export * from './logger';
10
10
  export * from './partitionAdapter';
11
11
  export * from './filter';
12
12
  export * from './unescape';
13
+ export * from './cache';
14
+ export * from './data-store';
15
+ export * from './http-client';
13
16
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../lib/index.ts"],"names":[],"mappings":"AAEA,cAAc,YAAY,CAAA;AAC1B,cAAc,UAAU,CAAA;AACxB,cAAc,aAAa,CAAA;AAC3B,cAAc,wBAAwB,CAAA;AACtC,cAAc,SAAS,CAAA;AACvB,cAAc,qBAAqB,CAAA;AACnC,cAAc,gCAAgC,CAAA;AAC9C,cAAc,YAAY,CAAA;AAC1B,cAAc,UAAU,CAAA;AACxB,cAAc,oBAAoB,CAAA;AAClC,cAAc,UAAU,CAAC;AACzB,cAAc,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../lib/index.ts"],"names":[],"mappings":"AAEA,cAAc,YAAY,CAAA;AAC1B,cAAc,UAAU,CAAA;AACxB,cAAc,aAAa,CAAA;AAC3B,cAAc,wBAAwB,CAAA;AACtC,cAAc,SAAS,CAAA;AACvB,cAAc,qBAAqB,CAAA;AACnC,cAAc,gCAAgC,CAAA;AAC9C,cAAc,YAAY,CAAA;AAC1B,cAAc,UAAU,CAAA;AACxB,cAAc,oBAAoB,CAAA;AAClC,cAAc,UAAU,CAAC;AACzB,cAAc,YAAY,CAAC;AAC3B,cAAc,SAAS,CAAC;AACxB,cAAc,cAAc,CAAC;AAC7B,cAAc,eAAe,CAAC"}
package/dist/lib/index.js CHANGED
@@ -27,4 +27,7 @@ __exportStar(require("./logger"), exports);
27
27
  __exportStar(require("./partitionAdapter"), exports);
28
28
  __exportStar(require("./filter"), exports);
29
29
  __exportStar(require("./unescape"), exports);
30
+ __exportStar(require("./cache"), exports);
31
+ __exportStar(require("./data-store"), exports);
32
+ __exportStar(require("./http-client"), exports);
30
33
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../lib/index.ts"],"names":[],"mappings":";AAAA,2EAA2E;;;;;;;;;;;;;;;;AAE3E,6CAA0B;AAC1B,2CAAwB;AACxB,8CAA2B;AAC3B,yDAAsC;AACtC,0CAAuB;AACvB,sDAAmC;AACnC,iEAA8C;AAC9C,6CAA0B;AAC1B,2CAAwB;AACxB,qDAAkC;AAClC,2CAAyB;AACzB,6CAA2B"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../lib/index.ts"],"names":[],"mappings":";AAAA,2EAA2E;;;;;;;;;;;;;;;;AAE3E,6CAA0B;AAC1B,2CAAwB;AACxB,8CAA2B;AAC3B,yDAAsC;AACtC,0CAAuB;AACvB,sDAAmC;AACnC,iEAA8C;AAC9C,6CAA0B;AAC1B,2CAAwB;AACxB,qDAAkC;AAClC,2CAAyB;AACzB,6CAA2B;AAC3B,0CAAwB;AACxB,+CAA6B;AAC7B,gDAA8B"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sailpoint/connector-sdk",
3
- "version": "1.1.41",
3
+ "version": "1.2.1",
4
4
  "description": "JavaScript framework to build SailPoint Connectors",
5
5
  "author": "SailPoint Technologies, Inc.",
6
6
  "license": "Copyright (c) 2023. SailPoint Technologies, Inc. All rights reserved.",
@@ -29,6 +29,7 @@
29
29
  },
30
30
  "dependencies": {
31
31
  "archiver": "^7.0.1",
32
+ "axios": "^1.14.0",
32
33
  "debug": "^4.4.1",
33
34
  "express": "^5.2.1",
34
35
  "jsep": "^1.4.0",