@transcend-io/sdk 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,256 @@
1
+ import { Logger } from "@transcend-io/utils";
2
+ import { GraphQLClient, RequestDocument, Variables } from "graphql-request";
3
+ import { Got } from "got";
4
+ import { DefaultConsentOption, IdentifierType, PreferenceStoreAuthLevel, PreferenceTopicType, RequestAction, SombraStandardScope } from "@transcend-io/privacy-types";
5
+ import { UserPrivacySignalEnum } from "@transcend-io/airgap.js-types";
6
+
7
+ //#region src/api/buildTranscendGraphQLClient.d.ts
8
+ /**
9
+ * Create a GraphQL client
10
+ *
11
+ * @param transcendUrl - Transcend API URL
12
+ * @param headers - Request headers to include in each request
13
+ * @param version - Optional version string to include in request headers
14
+ * @returns GraphQL client
15
+ */
16
+ declare function buildTranscendGraphQLClientGeneric(transcendUrl: string, headers: Record<string, string>, version?: string): GraphQLClient;
17
+ /**
18
+ * Create a GraphQL client capable of submitting requests with an API key
19
+ *
20
+ * @param transcendUrl - Transcend API URL
21
+ * @param auth - API key to authenticate to API
22
+ * @param version - Optional version string to include in request headers
23
+ * @returns GraphQL client
24
+ */
25
+ declare function buildTranscendGraphQLClient(transcendUrl: string, auth: string, version?: string): GraphQLClient;
26
+ //#endregion
27
+ //#region src/api/makeGraphQLRequest.d.ts
28
+ /**
29
+ * Make a GraphQL request with retries
30
+ *
31
+ * @param client - GraphQL client
32
+ * @param document - GraphQL document
33
+ * @param options - Options including logger, variables, headers, and retry config
34
+ * @returns Response
35
+ */
36
+ declare function makeGraphQLRequest<T, V extends Variables = Variables>(client: GraphQLClient, document: RequestDocument, options: {
37
+ /** GraphQL variables */variables?: V; /** Logger for retry/error messages */
38
+ logger: Logger; /** Additional request headers */
39
+ requestHeaders?: Record<string, string> | string[][] | Headers; /** Max number of retry attempts (default 4) */
40
+ maxRetries?: number;
41
+ }): Promise<T>;
42
+ //#endregion
43
+ //#region src/api/createSombraGotInstance.d.ts
44
+ /**
45
+ * Instantiate an instance of got that is capable of making requests
46
+ * to a sombra gateway.
47
+ *
48
+ * @param transcendUrl - URL of Transcend API
49
+ * @param transcendApiKey - Transcend API key
50
+ * @param options - Additional options
51
+ * @returns The instance of got that is capable of making requests to the customer ingress
52
+ */
53
+ declare function createSombraGotInstance(transcendUrl: string, transcendApiKey: string, options: {
54
+ /** Logger instance */logger: Logger; /** Sombra API key */
55
+ sombraApiKey?: string; /** Override Sombra URL (replaces process.env.SOMBRA_URL lookup) */
56
+ sombraUrl?: string;
57
+ }): Promise<Got>;
58
+ //#endregion
59
+ //#region src/data-inventory/fetchAllIdentifiers.d.ts
60
+ interface Identifier {
61
+ /** ID of identifier */
62
+ id: string;
63
+ /** Name of identifier */
64
+ name: string;
65
+ /** The type of identifier */
66
+ type: IdentifierType;
67
+ /** Regular expression */
68
+ regex: string;
69
+ /** The set of options that the identifier supports */
70
+ selectOptions: string[];
71
+ /** Whether identifier is enabled on privacy center */
72
+ privacyCenterVisibility: RequestAction[];
73
+ /** Enabled data subjects that are exposed this identifier on the privacy center */
74
+ dataSubjects: {
75
+ type: string;
76
+ }[];
77
+ /** Whether identifier is a required field in privacy center form */
78
+ isRequiredInForm: boolean;
79
+ /** Identifier placeholder text */
80
+ placeholder: string;
81
+ /** Display title for identifier */
82
+ displayTitle: {
83
+ defaultMessage: string;
84
+ };
85
+ /** Display description for identifier */
86
+ displayDescription: {
87
+ defaultMessage: string;
88
+ };
89
+ /** Display order */
90
+ displayOrder: number;
91
+ /** Does this identifier uniquely identify a consent record */
92
+ isUniqueOnPreferenceStore: boolean;
93
+ }
94
+ /**
95
+ * Fetch all identifiers in the organization
96
+ *
97
+ * @param client - GraphQL client
98
+ * @param options - Options
99
+ * @returns All identifiers in the organization
100
+ */
101
+ declare function fetchAllIdentifiers(client: GraphQLClient, options: {
102
+ logger: Logger;
103
+ }): Promise<Identifier[]>;
104
+ //#endregion
105
+ //#region src/preference-management/fetchAllPurposes.d.ts
106
+ interface Purpose {
107
+ /** ID of purpose */
108
+ id: string;
109
+ /** Name of purpose */
110
+ name: string;
111
+ /** Description of purpose */
112
+ description: string;
113
+ /** Default consent status */
114
+ defaultConsent: DefaultConsentOption;
115
+ /** Slug of purpose */
116
+ trackingType: string;
117
+ /** Whether the purpose is configurable */
118
+ configurable: boolean;
119
+ /** Whether the purpose is essential */
120
+ essential: boolean;
121
+ /** Whether to show the purpose in the consent manager */
122
+ showInConsentManager: boolean;
123
+ /** Whether the purpose is active */
124
+ isActive: boolean;
125
+ /** Display order of the purpose */
126
+ displayOrder: number;
127
+ /** Opt-out signals for the purpose */
128
+ optOutSignals: UserPrivacySignalEnum[];
129
+ /** Whether the purpose is deleted */
130
+ deletedAt?: string;
131
+ /** Authorization level required for the purpose */
132
+ authLevel: PreferenceStoreAuthLevel;
133
+ /** Whether to show the purpose in the privacy center */
134
+ showInPrivacyCenter: boolean;
135
+ /** Title of the purpose */
136
+ title: string;
137
+ }
138
+ /**
139
+ * Fetch all purposes in the organization
140
+ *
141
+ * @param client - GraphQL client
142
+ * @param options - Options
143
+ * @returns All purposes in the organization
144
+ */
145
+ declare function fetchAllPurposes(client: GraphQLClient, options: {
146
+ /** Logger instance */logger: Logger; /** Whether to include deleted purposes */
147
+ includeDeleted?: boolean;
148
+ }): Promise<Purpose[]>;
149
+ //#endregion
150
+ //#region src/preference-management/fetchAllPreferenceTopics.d.ts
151
+ interface PreferenceTopic {
152
+ /** ID of preference topic */
153
+ id: string;
154
+ /** Slug of preference topic */
155
+ slug: string;
156
+ /** Title of topic */
157
+ title: {
158
+ id: string; /** Default message */
159
+ defaultMessage: string;
160
+ };
161
+ /** Whether to show in privacy center */
162
+ showInPrivacyCenter: boolean;
163
+ /** Description to display in privacy center */
164
+ displayDescription: {
165
+ id: string; /** Default message */
166
+ defaultMessage: string;
167
+ };
168
+ /** Type of preference topic */
169
+ type: PreferenceTopicType;
170
+ /** Default configuration */
171
+ defaultConfiguration: string;
172
+ /** Option values */
173
+ preferenceOptionValues: {
174
+ /** Slug of value */slug: string; /** Title of value */
175
+ title: {
176
+ id: string; /** Default message */
177
+ defaultMessage: string;
178
+ };
179
+ }[];
180
+ /** Related purpose */
181
+ purpose: {
182
+ trackingType: string;
183
+ };
184
+ }
185
+ /**
186
+ * Fetch all preference topics in the organization
187
+ *
188
+ * @param client - GraphQL client
189
+ * @param options - Options
190
+ * @returns All preference topics in the organization
191
+ */
192
+ declare function fetchAllPreferenceTopics(client: GraphQLClient, options: {
193
+ /** Logger instance */logger: Logger;
194
+ }): Promise<PreferenceTopic[]>;
195
+ //#endregion
196
+ //#region src/preference-management/fetchAllPurposesAndPreferences.d.ts
197
+ interface PurposeWithPreferences extends Purpose {
198
+ /** Topics */
199
+ topics: PreferenceTopic[];
200
+ }
201
+ /**
202
+ * Fetch all purposes and preferences
203
+ *
204
+ * @param client - GraphQL client
205
+ * @param options - Options
206
+ * @returns List of purposes with their preference topics
207
+ */
208
+ declare function fetchAllPurposesAndPreferences(client: GraphQLClient, options: {
209
+ logger: Logger;
210
+ }): Promise<PurposeWithPreferences[]>;
211
+ //#endregion
212
+ //#region src/preference-management/createPreferenceAccessTokens.d.ts
213
+ interface PreferenceAccessTokenInput {
214
+ /** Slug of data subject to authenticate as */
215
+ subjectType: string;
216
+ /** Scopes to grant */
217
+ scopes: SombraStandardScope[];
218
+ /** Expiration time in seconds */
219
+ expiresIn?: number;
220
+ /** Email address of user */
221
+ email: string;
222
+ /** Core identifier for the user */
223
+ coreIdentifier?: string;
224
+ }
225
+ interface PreferenceAccessTokenInputWithIndex extends PreferenceAccessTokenInput {
226
+ /** Index of the input record */
227
+ index?: number;
228
+ }
229
+ /**
230
+ * Create preference access tokens for the given identifiers.
231
+ *
232
+ * @see https://docs.transcend.io/docs/articles/preference-management/access-links
233
+ * @param client - GraphQL client
234
+ * @param options - Options
235
+ * @returns list of access tokens/input identifiers
236
+ */
237
+ declare function createPreferenceAccessTokens(client: GraphQLClient, options: {
238
+ /** Records to create tokens for */records: PreferenceAccessTokenInputWithIndex[]; /** Logger instance */
239
+ logger: Logger; /** Optional progress emitter */
240
+ emitProgress?: (progress: number) => void; /** Number of concurrent requests to make (default: 10) */
241
+ concurrency?: number;
242
+ }): Promise<{
243
+ /** Identifier for the record */input: PreferenceAccessTokenInputWithIndex; /** Access token */
244
+ accessToken: string;
245
+ }[]>;
246
+ //#endregion
247
+ //#region src/index.d.ts
248
+ interface MonorepoPackageDefinition {
249
+ directory: string;
250
+ displayName: string;
251
+ packageName: string;
252
+ }
253
+ declare function createMonorepoPackageDefinition(name: string, directory: string): MonorepoPackageDefinition;
254
+ //#endregion
255
+ export { Identifier, MonorepoPackageDefinition, PreferenceAccessTokenInput, PreferenceAccessTokenInputWithIndex, PreferenceTopic, Purpose, PurposeWithPreferences, buildTranscendGraphQLClient, buildTranscendGraphQLClientGeneric, createMonorepoPackageDefinition, createPreferenceAccessTokens, createSombraGotInstance, fetchAllIdentifiers, fetchAllPreferenceTopics, fetchAllPurposes, fetchAllPurposesAndPreferences, makeGraphQLRequest };
256
+ //# sourceMappingURL=index.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/api/buildTranscendGraphQLClient.ts","../src/api/makeGraphQLRequest.ts","../src/api/createSombraGotInstance.ts","../src/data-inventory/fetchAllIdentifiers.ts","../src/preference-management/fetchAllPurposes.ts","../src/preference-management/fetchAllPreferenceTopics.ts","../src/preference-management/fetchAllPurposesAndPreferences.ts","../src/preference-management/createPreferenceAccessTokens.ts","../src/index.ts"],"mappings":"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"}
package/dist/index.mjs ADDED
@@ -0,0 +1,377 @@
1
+ import { describePackageName, map, sleepPromise } from "@transcend-io/utils";
2
+ import { GraphQLClient, gql } from "graphql-request";
3
+ import got from "got";
4
+ import { parse } from "graphql";
5
+ import { chunk } from "lodash-es";
6
+ //#region src/api/buildTranscendGraphQLClient.ts
7
+ /**
8
+ * Create a GraphQL client
9
+ *
10
+ * @param transcendUrl - Transcend API URL
11
+ * @param headers - Request headers to include in each request
12
+ * @param version - Optional version string to include in request headers
13
+ * @returns GraphQL client
14
+ */
15
+ function buildTranscendGraphQLClientGeneric(transcendUrl, headers, version) {
16
+ return new GraphQLClient(`${transcendUrl}/graphql`, { headers: {
17
+ ...headers,
18
+ ...version ? { version } : {}
19
+ } });
20
+ }
21
+ /**
22
+ * Create a GraphQL client capable of submitting requests with an API key
23
+ *
24
+ * @param transcendUrl - Transcend API URL
25
+ * @param auth - API key to authenticate to API
26
+ * @param version - Optional version string to include in request headers
27
+ * @returns GraphQL client
28
+ */
29
+ function buildTranscendGraphQLClient(transcendUrl, auth, version) {
30
+ return buildTranscendGraphQLClientGeneric(transcendUrl, { Authorization: `Bearer ${auth}` }, version);
31
+ }
32
+ //#endregion
33
+ //#region src/api/makeGraphQLRequest.ts
34
+ const DEFAULT_MAX_RETRIES = 4;
35
+ const KNOWN_ERRORS = [
36
+ "syntax error",
37
+ "got invalid value",
38
+ "Client error",
39
+ "cannot affect row a second time",
40
+ "GRAPHQL_VALIDATION_FAILED"
41
+ ];
42
+ /**
43
+ * Make a GraphQL request with retries
44
+ *
45
+ * @param client - GraphQL client
46
+ * @param document - GraphQL document
47
+ * @param options - Options including logger, variables, headers, and retry config
48
+ * @returns Response
49
+ */
50
+ async function makeGraphQLRequest(client, document, options) {
51
+ const { variables, logger, requestHeaders, maxRetries = DEFAULT_MAX_RETRIES } = options;
52
+ let retryCount = 0;
53
+ while (true) try {
54
+ return await client.request(document, variables, requestHeaders);
55
+ } catch (err) {
56
+ if (err.message?.includes("API key is invalid")) throw new Error("API key is invalid. Please ensure that the key provided has the proper scope and is not expired, and that the transcendUrl corresponds to the correct backend for your organization.");
57
+ if (KNOWN_ERRORS.some((msg) => err.message?.includes(msg))) throw err;
58
+ if (err.message?.startsWith("Client error: Too many requests")) {
59
+ const rateLimitResetAt = err.response?.headers?.get("x-ratelimit-reset");
60
+ const sleepTime = rateLimitResetAt ? new Date(rateLimitResetAt).getTime() - (/* @__PURE__ */ new Date()).getTime() + 100 : 1e3 * 10;
61
+ logger.warn(`DETECTED RATE LIMIT: ${err.message}. Sleeping for ${sleepTime}ms`);
62
+ await sleepPromise(sleepTime);
63
+ }
64
+ if (retryCount >= maxRetries) throw err;
65
+ retryCount += 1;
66
+ logger.warn(`Retrying failed request (${retryCount} / ${maxRetries}): ${err.message}`);
67
+ }
68
+ }
69
+ //#endregion
70
+ //#region src/api/gqls/organization.ts
71
+ const ORGANIZATION = parse(gql`
72
+ query TranscendCliOrganization {
73
+ organization {
74
+ sombra {
75
+ customerUrl
76
+ }
77
+ }
78
+ }
79
+ `);
80
+ //#endregion
81
+ //#region src/api/createSombraGotInstance.ts
82
+ /**
83
+ * Instantiate an instance of got that is capable of making requests
84
+ * to a sombra gateway.
85
+ *
86
+ * @param transcendUrl - URL of Transcend API
87
+ * @param transcendApiKey - Transcend API key
88
+ * @param options - Additional options
89
+ * @returns The instance of got that is capable of making requests to the customer ingress
90
+ */
91
+ async function createSombraGotInstance(transcendUrl, transcendApiKey, options) {
92
+ const { logger, sombraApiKey, sombraUrl } = options;
93
+ const { organization } = await makeGraphQLRequest(buildTranscendGraphQLClient(transcendUrl, transcendApiKey), ORGANIZATION, { logger });
94
+ const { customerUrl } = organization.sombra;
95
+ const sombraToUse = sombraUrl || customerUrl;
96
+ if (!sombraUrl && ["https://sombra-reverse-tunnel.transcend.io", "https://sombra-reverse-tunnel.us.transcend.io"].includes(customerUrl)) throw new Error("It looks like your Sombra customer ingress URL has not been set up. Please follow the instructions here to configure networking for Sombra: https://docs.transcend.io/docs/articles/sombra/deploying/customizing-sombra/networking");
97
+ logger.info(`Using sombra: ${sombraToUse}`);
98
+ return got.extend({
99
+ prefixUrl: sombraToUse,
100
+ headers: {
101
+ Authorization: `Bearer ${transcendApiKey}`,
102
+ ...sombraApiKey ? { "X-Sombra-Authorization": `Bearer ${sombraApiKey}` } : {}
103
+ }
104
+ });
105
+ }
106
+ //#endregion
107
+ //#region src/data-inventory/gqls/identifier.ts
108
+ const IDENTIFIERS = parse(gql`
109
+ query TranscendCliIdentifiers($first: Int!, $offset: Int!) {
110
+ identifiers(
111
+ first: $first
112
+ offset: $offset
113
+ useMaster: false
114
+ orderBy: [{ field: createdAt, direction: ASC }, { field: name, direction: ASC }]
115
+ ) {
116
+ nodes {
117
+ id
118
+ name
119
+ type
120
+ regex
121
+ selectOptions
122
+ privacyCenterVisibility
123
+ dataSubjects {
124
+ type
125
+ }
126
+ isRequiredInForm
127
+ placeholder
128
+ displayTitle {
129
+ defaultMessage
130
+ }
131
+ displayDescription {
132
+ defaultMessage
133
+ }
134
+ displayOrder
135
+ isUniqueOnPreferenceStore
136
+ }
137
+ }
138
+ }
139
+ `);
140
+ //#endregion
141
+ //#region src/data-inventory/fetchAllIdentifiers.ts
142
+ const PAGE_SIZE$2 = 20;
143
+ /**
144
+ * Fetch all identifiers in the organization
145
+ *
146
+ * @param client - GraphQL client
147
+ * @param options - Options
148
+ * @returns All identifiers in the organization
149
+ */
150
+ async function fetchAllIdentifiers(client, options) {
151
+ const { logger } = options;
152
+ const identifiers = [];
153
+ let offset = 0;
154
+ let shouldContinue = false;
155
+ do {
156
+ const { identifiers: { nodes } } = await makeGraphQLRequest(client, IDENTIFIERS, {
157
+ logger,
158
+ variables: {
159
+ first: PAGE_SIZE$2,
160
+ offset
161
+ }
162
+ });
163
+ identifiers.push(...nodes);
164
+ offset += PAGE_SIZE$2;
165
+ shouldContinue = nodes.length === PAGE_SIZE$2;
166
+ } while (shouldContinue);
167
+ return identifiers.sort((a, b) => a.name.localeCompare(b.name));
168
+ }
169
+ //#endregion
170
+ //#region src/preference-management/gqls/purpose.ts
171
+ const PURPOSES = parse(gql`
172
+ query TranscendCliPurposes(
173
+ $first: Int!
174
+ $offset: Int!
175
+ $filterBy: TrackingPurposeFiltersInput
176
+ $input: TrackingPurposeInput!
177
+ ) {
178
+ purposes(first: $first, offset: $offset, filterBy: $filterBy, input: $input) {
179
+ nodes {
180
+ id
181
+ name
182
+ description
183
+ defaultConsent
184
+ trackingType
185
+ configurable
186
+ essential
187
+ showInConsentManager
188
+ isActive
189
+ displayOrder
190
+ optOutSignals
191
+ deletedAt
192
+ authLevel
193
+ showInPrivacyCenter
194
+ title
195
+ }
196
+ }
197
+ }
198
+ `);
199
+ //#endregion
200
+ //#region src/preference-management/fetchAllPurposes.ts
201
+ const PAGE_SIZE$1 = 20;
202
+ /**
203
+ * Fetch all purposes in the organization
204
+ *
205
+ * @param client - GraphQL client
206
+ * @param options - Options
207
+ * @returns All purposes in the organization
208
+ */
209
+ async function fetchAllPurposes(client, options) {
210
+ const { logger, includeDeleted = false } = options;
211
+ const purposes = [];
212
+ let offset = 0;
213
+ let shouldContinue = false;
214
+ do {
215
+ const { purposes: { nodes } } = await makeGraphQLRequest(client, PURPOSES, {
216
+ logger,
217
+ variables: {
218
+ first: PAGE_SIZE$1,
219
+ offset,
220
+ input: { includeDeleted }
221
+ }
222
+ });
223
+ purposes.push(...nodes);
224
+ offset += PAGE_SIZE$1;
225
+ shouldContinue = nodes.length === PAGE_SIZE$1;
226
+ } while (shouldContinue);
227
+ return purposes.sort((a, b) => a.trackingType.localeCompare(b.trackingType));
228
+ }
229
+ //#endregion
230
+ //#region src/preference-management/gqls/preferenceTopic.ts
231
+ const PREFERENCE_TOPICS = parse(gql`
232
+ query TranscendCliPreferenceTopics(
233
+ $first: Int!
234
+ $offset: Int!
235
+ $filterBy: PreferenceTopicFilterInput
236
+ ) {
237
+ preferenceTopics(first: $first, offset: $offset, filterBy: $filterBy) {
238
+ nodes {
239
+ id
240
+ slug
241
+ type
242
+ title {
243
+ id
244
+ defaultMessage
245
+ }
246
+ showInPrivacyCenter
247
+ displayDescription {
248
+ id
249
+ defaultMessage
250
+ }
251
+ defaultConfiguration
252
+ preferenceOptionValues {
253
+ slug
254
+ title {
255
+ id
256
+ defaultMessage
257
+ }
258
+ }
259
+ purpose {
260
+ trackingType
261
+ }
262
+ }
263
+ }
264
+ }
265
+ `);
266
+ //#endregion
267
+ //#region src/preference-management/fetchAllPreferenceTopics.ts
268
+ const PAGE_SIZE = 20;
269
+ /**
270
+ * Fetch all preference topics in the organization
271
+ *
272
+ * @param client - GraphQL client
273
+ * @param options - Options
274
+ * @returns All preference topics in the organization
275
+ */
276
+ async function fetchAllPreferenceTopics(client, options) {
277
+ const { logger } = options;
278
+ const preferenceTopics = [];
279
+ let offset = 0;
280
+ let shouldContinue = false;
281
+ do {
282
+ const { preferenceTopics: { nodes } } = await makeGraphQLRequest(client, PREFERENCE_TOPICS, {
283
+ logger,
284
+ variables: {
285
+ first: PAGE_SIZE,
286
+ offset
287
+ }
288
+ });
289
+ preferenceTopics.push(...nodes);
290
+ offset += PAGE_SIZE;
291
+ shouldContinue = nodes.length === PAGE_SIZE;
292
+ } while (shouldContinue);
293
+ return preferenceTopics.sort((a, b) => `${a.slug}:${a.purpose.trackingType}`.localeCompare(`${b.slug}:${b.purpose.trackingType}`));
294
+ }
295
+ //#endregion
296
+ //#region src/preference-management/fetchAllPurposesAndPreferences.ts
297
+ /**
298
+ * Fetch all purposes and preferences
299
+ *
300
+ * @param client - GraphQL client
301
+ * @param options - Options
302
+ * @returns List of purposes with their preference topics
303
+ */
304
+ async function fetchAllPurposesAndPreferences(client, options) {
305
+ const [purposes, topics] = await Promise.all([fetchAllPurposes(client, options), fetchAllPreferenceTopics(client, options)]);
306
+ return purposes.map((purpose) => ({
307
+ ...purpose,
308
+ topics: topics.filter((topic) => topic.purpose.trackingType === purpose.trackingType)
309
+ }));
310
+ }
311
+ //#endregion
312
+ //#region src/preference-management/gqls/preferenceAccessTokens.ts
313
+ const CREATE_PREFERENCE_ACCESS_TOKENS = parse(gql`
314
+ mutation TranscendCliCreatePreferenceAccessTokens($input: CreatePrivacyCenterAccessTokensInput!) {
315
+ createPrivacyCenterAccessTokens(input: $input) {
316
+ nodes {
317
+ token
318
+ }
319
+ }
320
+ }
321
+ `);
322
+ //#endregion
323
+ //#region src/preference-management/createPreferenceAccessTokens.ts
324
+ const MAX_BATCH_SIZE = 50;
325
+ /**
326
+ * Create preference access tokens for a single page of identifiers.
327
+ *
328
+ * @param client - GraphQL client
329
+ * @param records - Inputs to sign
330
+ * @param logger - Logger
331
+ * @returns list of access tokens
332
+ */
333
+ async function createPreferenceAccessTokensPage(client, records, logger) {
334
+ const { createPrivacyCenterAccessTokens: { nodes } } = await makeGraphQLRequest(client, CREATE_PREFERENCE_ACCESS_TOKENS, {
335
+ logger,
336
+ variables: { input: { records } }
337
+ });
338
+ return nodes.map((node) => node.token);
339
+ }
340
+ /**
341
+ * Create preference access tokens for the given identifiers.
342
+ *
343
+ * @see https://docs.transcend.io/docs/articles/preference-management/access-links
344
+ * @param client - GraphQL client
345
+ * @param options - Options
346
+ * @returns list of access tokens/input identifiers
347
+ */
348
+ async function createPreferenceAccessTokens(client, options) {
349
+ const { records, logger, emitProgress, concurrency = 10 } = options;
350
+ let completed = 0;
351
+ emitProgress?.(0);
352
+ const results = [];
353
+ await map(chunk(records, MAX_BATCH_SIZE), async (chunkedRecords) => {
354
+ const mappedResults = (await createPreferenceAccessTokensPage(client, chunkedRecords.map(({ index, ...rest }) => rest), logger)).map((token, idx) => ({
355
+ input: chunkedRecords[idx],
356
+ accessToken: token
357
+ }));
358
+ results.push(...mappedResults);
359
+ completed += chunkedRecords.length;
360
+ emitProgress?.(completed);
361
+ }, { concurrency });
362
+ return results;
363
+ }
364
+ //#endregion
365
+ //#region src/index.ts
366
+ function createMonorepoPackageDefinition(name, directory) {
367
+ const packageNameParts = describePackageName(name);
368
+ return {
369
+ directory,
370
+ displayName: packageNameParts.displayName,
371
+ packageName: `@transcend-io/${packageNameParts.slug}`
372
+ };
373
+ }
374
+ //#endregion
375
+ export { buildTranscendGraphQLClient, buildTranscendGraphQLClientGeneric, createMonorepoPackageDefinition, createPreferenceAccessTokens, createSombraGotInstance, fetchAllIdentifiers, fetchAllPreferenceTopics, fetchAllPurposes, fetchAllPurposesAndPreferences, makeGraphQLRequest };
376
+
377
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","names":["PAGE_SIZE","PAGE_SIZE"],"sources":["../src/api/buildTranscendGraphQLClient.ts","../src/api/makeGraphQLRequest.ts","../src/api/gqls/organization.ts","../src/api/createSombraGotInstance.ts","../src/data-inventory/gqls/identifier.ts","../src/data-inventory/fetchAllIdentifiers.ts","../src/preference-management/gqls/purpose.ts","../src/preference-management/fetchAllPurposes.ts","../src/preference-management/gqls/preferenceTopic.ts","../src/preference-management/fetchAllPreferenceTopics.ts","../src/preference-management/fetchAllPurposesAndPreferences.ts","../src/preference-management/gqls/preferenceAccessTokens.ts","../src/preference-management/createPreferenceAccessTokens.ts","../src/index.ts"],"sourcesContent":["import { GraphQLClient } from 'graphql-request';\n\n/**\n * Create a GraphQL client\n *\n * @param transcendUrl - Transcend API URL\n * @param headers - Request headers to include in each request\n * @param version - Optional version string to include in request headers\n * @returns GraphQL client\n */\nexport function buildTranscendGraphQLClientGeneric(\n transcendUrl: string,\n headers: Record<string, string>,\n version?: string,\n): GraphQLClient {\n return new GraphQLClient(`${transcendUrl}/graphql`, {\n headers: {\n ...headers,\n ...(version ? { version } : {}),\n },\n });\n}\n\n/**\n * Create a GraphQL client capable of submitting requests with an API key\n *\n * @param transcendUrl - Transcend API URL\n * @param auth - API key to authenticate to API\n * @param version - Optional version string to include in request headers\n * @returns GraphQL client\n */\nexport function buildTranscendGraphQLClient(\n transcendUrl: string,\n auth: string,\n version?: string,\n): GraphQLClient {\n return buildTranscendGraphQLClientGeneric(\n transcendUrl,\n { Authorization: `Bearer ${auth}` },\n version,\n );\n}\n","import { sleepPromise, type Logger } from '@transcend-io/utils';\nimport type { GraphQLClient, RequestDocument, Variables } from 'graphql-request';\n\nconst DEFAULT_MAX_RETRIES = 4;\n\nconst KNOWN_ERRORS = [\n 'syntax error',\n 'got invalid value',\n 'Client error',\n 'cannot affect row a second time',\n 'GRAPHQL_VALIDATION_FAILED',\n];\n\n/**\n * Make a GraphQL request with retries\n *\n * @param client - GraphQL client\n * @param document - GraphQL document\n * @param options - Options including logger, variables, headers, and retry config\n * @returns Response\n */\nexport async function makeGraphQLRequest<T, V extends Variables = Variables>(\n client: GraphQLClient,\n document: RequestDocument,\n options: {\n /** GraphQL variables */\n variables?: V;\n /** Logger for retry/error messages */\n logger: Logger;\n /** Additional request headers */\n requestHeaders?: Record<string, string> | string[][] | Headers;\n /** Max number of retry attempts (default 4) */\n maxRetries?: number;\n },\n): Promise<T> {\n const { variables, logger, requestHeaders, maxRetries = DEFAULT_MAX_RETRIES } = options;\n\n let retryCount = 0;\n // eslint-disable-next-line no-constant-condition\n while (true) {\n try {\n const result = await client.request(document, variables, requestHeaders);\n return result as T;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n } catch (err: any) {\n if (err.message?.includes('API key is invalid')) {\n throw new Error(\n 'API key is invalid. ' +\n 'Please ensure that the key provided has the proper scope and is not expired, ' +\n 'and that the transcendUrl corresponds to the correct backend for your organization.',\n );\n }\n\n if (KNOWN_ERRORS.some((msg) => err.message?.includes(msg))) {\n throw err;\n }\n\n if (err.message?.startsWith('Client error: Too many requests')) {\n const rateLimitResetAt = err.response?.headers?.get('x-ratelimit-reset');\n const sleepTime = rateLimitResetAt\n ? new Date(rateLimitResetAt).getTime() - new Date().getTime() + 100\n : 1000 * 10;\n logger.warn(`DETECTED RATE LIMIT: ${err.message}. Sleeping for ${sleepTime}ms`);\n await sleepPromise(sleepTime);\n }\n\n if (retryCount >= maxRetries) {\n throw err;\n }\n retryCount += 1;\n logger.warn(`Retrying failed request (${retryCount} / ${maxRetries}): ${err.message}`);\n }\n }\n}\n","import { parse, type DocumentNode } from 'graphql';\nimport { gql } from 'graphql-request';\n\nexport const ORGANIZATION: DocumentNode = parse(gql`\n query TranscendCliOrganization {\n organization {\n sombra {\n customerUrl\n }\n }\n }\n`);\n","import type { Logger } from '@transcend-io/utils';\nimport got, { type Got } from 'got';\n\nimport { buildTranscendGraphQLClient } from './buildTranscendGraphQLClient.js';\nimport { ORGANIZATION } from './gqls/organization.js';\nimport { makeGraphQLRequest } from './makeGraphQLRequest.js';\n\n/**\n * Instantiate an instance of got that is capable of making requests\n * to a sombra gateway.\n *\n * @param transcendUrl - URL of Transcend API\n * @param transcendApiKey - Transcend API key\n * @param options - Additional options\n * @returns The instance of got that is capable of making requests to the customer ingress\n */\nexport async function createSombraGotInstance(\n transcendUrl: string,\n transcendApiKey: string,\n options: {\n /** Logger instance */\n logger: Logger;\n /** Sombra API key */\n sombraApiKey?: string;\n /** Override Sombra URL (replaces process.env.SOMBRA_URL lookup) */\n sombraUrl?: string;\n },\n): Promise<Got> {\n const { logger, sombraApiKey, sombraUrl } = options;\n\n const client = buildTranscendGraphQLClient(transcendUrl, transcendApiKey);\n const { organization } = await makeGraphQLRequest<{\n /** Organization */\n organization: {\n /** Primary Sombra */\n sombra: {\n /** URL */\n customerUrl: string;\n };\n };\n }>(client, ORGANIZATION, { logger });\n\n const { customerUrl } = organization.sombra;\n const sombraToUse = sombraUrl || customerUrl;\n\n if (\n !sombraUrl &&\n [\n 'https://sombra-reverse-tunnel.transcend.io',\n 'https://sombra-reverse-tunnel.us.transcend.io',\n ].includes(customerUrl)\n ) {\n throw new Error(\n 'It looks like your Sombra customer ingress URL has not been set up. ' +\n 'Please follow the instructions here to configure networking for Sombra: ' +\n 'https://docs.transcend.io/docs/articles/sombra/deploying/customizing-sombra/networking',\n );\n }\n logger.info(`Using sombra: ${sombraToUse}`);\n\n return got.extend({\n prefixUrl: sombraToUse,\n headers: {\n Authorization: `Bearer ${transcendApiKey}`,\n ...(sombraApiKey ? { 'X-Sombra-Authorization': `Bearer ${sombraApiKey}` } : {}),\n },\n });\n}\n","import { parse, type DocumentNode } from 'graphql';\nimport { gql } from 'graphql-request';\n\nexport const IDENTIFIERS: DocumentNode = parse(gql`\n query TranscendCliIdentifiers($first: Int!, $offset: Int!) {\n identifiers(\n first: $first\n offset: $offset\n useMaster: false\n orderBy: [{ field: createdAt, direction: ASC }, { field: name, direction: ASC }]\n ) {\n nodes {\n id\n name\n type\n regex\n selectOptions\n privacyCenterVisibility\n dataSubjects {\n type\n }\n isRequiredInForm\n placeholder\n displayTitle {\n defaultMessage\n }\n displayDescription {\n defaultMessage\n }\n displayOrder\n isUniqueOnPreferenceStore\n }\n }\n }\n`);\n","import { IdentifierType, RequestAction } from '@transcend-io/privacy-types';\nimport type { Logger } from '@transcend-io/utils';\nimport type { GraphQLClient } from 'graphql-request';\n\nimport { makeGraphQLRequest } from '../api/makeGraphQLRequest.js';\nimport { IDENTIFIERS } from './gqls/identifier.js';\n\nexport interface Identifier {\n /** ID of identifier */\n id: string;\n /** Name of identifier */\n name: string;\n /** The type of identifier */\n type: IdentifierType;\n /** Regular expression */\n regex: string;\n /** The set of options that the identifier supports */\n selectOptions: string[];\n /** Whether identifier is enabled on privacy center */\n privacyCenterVisibility: RequestAction[];\n /** Enabled data subjects that are exposed this identifier on the privacy center */\n dataSubjects: { /** type of data subjects */ type: string }[];\n /** Whether identifier is a required field in privacy center form */\n isRequiredInForm: boolean;\n /** Identifier placeholder text */\n placeholder: string;\n /** Display title for identifier */\n displayTitle: { /** Default message */ defaultMessage: string };\n /** Display description for identifier */\n displayDescription: { /** Default */ defaultMessage: string };\n /** Display order */\n displayOrder: number;\n /** Does this identifier uniquely identify a consent record */\n isUniqueOnPreferenceStore: boolean;\n}\n\nconst PAGE_SIZE = 20;\n\n/**\n * Fetch all identifiers in the organization\n *\n * @param client - GraphQL client\n * @param options - Options\n * @returns All identifiers in the organization\n */\nexport async function fetchAllIdentifiers(\n client: GraphQLClient,\n options: { /** Logger instance */ logger: Logger },\n): Promise<Identifier[]> {\n const { logger } = options;\n const identifiers: Identifier[] = [];\n let offset = 0;\n\n let shouldContinue = false;\n do {\n const {\n identifiers: { nodes },\n } = await makeGraphQLRequest<{\n /** Identifiers */\n identifiers: { /** List */ nodes: Identifier[] };\n }>(client, IDENTIFIERS, {\n logger,\n variables: { first: PAGE_SIZE, offset },\n });\n identifiers.push(...nodes);\n offset += PAGE_SIZE;\n shouldContinue = nodes.length === PAGE_SIZE;\n } while (shouldContinue);\n\n return identifiers.sort((a, b) => a.name.localeCompare(b.name));\n}\n","import { parse, type DocumentNode } from 'graphql';\nimport { gql } from 'graphql-request';\n\nexport const PURPOSES: DocumentNode = parse(gql`\n query TranscendCliPurposes(\n $first: Int!\n $offset: Int!\n $filterBy: TrackingPurposeFiltersInput\n $input: TrackingPurposeInput!\n ) {\n purposes(first: $first, offset: $offset, filterBy: $filterBy, input: $input) {\n nodes {\n id\n name\n description\n defaultConsent\n trackingType\n configurable\n essential\n showInConsentManager\n isActive\n displayOrder\n optOutSignals\n deletedAt\n authLevel\n showInPrivacyCenter\n title\n }\n }\n }\n`);\n","import { UserPrivacySignalEnum } from '@transcend-io/airgap.js-types';\nimport { DefaultConsentOption, PreferenceStoreAuthLevel } from '@transcend-io/privacy-types';\nimport type { Logger } from '@transcend-io/utils';\nimport type { GraphQLClient } from 'graphql-request';\n\nimport { makeGraphQLRequest } from '../api/makeGraphQLRequest.js';\nimport { PURPOSES } from './gqls/purpose.js';\n\nexport interface Purpose {\n /** ID of purpose */\n id: string;\n /** Name of purpose */\n name: string;\n /** Description of purpose */\n description: string;\n /** Default consent status */\n defaultConsent: DefaultConsentOption;\n /** Slug of purpose */\n trackingType: string;\n /** Whether the purpose is configurable */\n configurable: boolean;\n /** Whether the purpose is essential */\n essential: boolean;\n /** Whether to show the purpose in the consent manager */\n showInConsentManager: boolean;\n /** Whether the purpose is active */\n isActive: boolean;\n /** Display order of the purpose */\n displayOrder: number;\n /** Opt-out signals for the purpose */\n optOutSignals: UserPrivacySignalEnum[];\n /** Whether the purpose is deleted */\n deletedAt?: string;\n /** Authorization level required for the purpose */\n authLevel: PreferenceStoreAuthLevel;\n /** Whether to show the purpose in the privacy center */\n showInPrivacyCenter: boolean;\n /** Title of the purpose */\n title: string;\n}\n\nconst PAGE_SIZE = 20;\n\n/**\n * Fetch all purposes in the organization\n *\n * @param client - GraphQL client\n * @param options - Options\n * @returns All purposes in the organization\n */\nexport async function fetchAllPurposes(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger: Logger;\n /** Whether to include deleted purposes */\n includeDeleted?: boolean;\n },\n): Promise<Purpose[]> {\n const { logger, includeDeleted = false } = options;\n const purposes: Purpose[] = [];\n let offset = 0;\n\n let shouldContinue = false;\n do {\n const {\n purposes: { nodes },\n } = await makeGraphQLRequest<{\n /** Purposes */\n purposes: { /** List */ nodes: Purpose[] };\n }>(client, PURPOSES, {\n logger,\n variables: { first: PAGE_SIZE, offset, input: { includeDeleted } },\n });\n purposes.push(...nodes);\n offset += PAGE_SIZE;\n shouldContinue = nodes.length === PAGE_SIZE;\n } while (shouldContinue);\n\n return purposes.sort((a, b) => a.trackingType.localeCompare(b.trackingType));\n}\n","import { parse, type DocumentNode } from 'graphql';\nimport { gql } from 'graphql-request';\n\nexport const PREFERENCE_TOPICS: DocumentNode = parse(gql`\n query TranscendCliPreferenceTopics(\n $first: Int!\n $offset: Int!\n $filterBy: PreferenceTopicFilterInput\n ) {\n preferenceTopics(first: $first, offset: $offset, filterBy: $filterBy) {\n nodes {\n id\n slug\n type\n title {\n id\n defaultMessage\n }\n showInPrivacyCenter\n displayDescription {\n id\n defaultMessage\n }\n defaultConfiguration\n preferenceOptionValues {\n slug\n title {\n id\n defaultMessage\n }\n }\n purpose {\n trackingType\n }\n }\n }\n }\n`);\n","import { PreferenceTopicType } from '@transcend-io/privacy-types';\nimport type { Logger } from '@transcend-io/utils';\nimport type { GraphQLClient } from 'graphql-request';\n\nimport { makeGraphQLRequest } from '../api/makeGraphQLRequest.js';\nimport { PREFERENCE_TOPICS } from './gqls/preferenceTopic.js';\n\nexport interface PreferenceTopic {\n /** ID of preference topic */\n id: string;\n /** Slug of preference topic */\n slug: string;\n /** Title of topic */\n title: { /** ID */ id: string; /** Default message */ defaultMessage: string };\n /** Whether to show in privacy center */\n showInPrivacyCenter: boolean;\n /** Description to display in privacy center */\n displayDescription: { /** ID */ id: string; /** Default message */ defaultMessage: string };\n /** Type of preference topic */\n type: PreferenceTopicType;\n /** Default configuration */\n defaultConfiguration: string;\n /** Option values */\n preferenceOptionValues: {\n /** Slug of value */\n slug: string;\n /** Title of value */\n title: { /** ID */ id: string; /** Default message */ defaultMessage: string };\n }[];\n /** Related purpose */\n purpose: { /** Slug */ trackingType: string };\n}\n\nconst PAGE_SIZE = 20;\n\n/**\n * Fetch all preference topics in the organization\n *\n * @param client - GraphQL client\n * @param options - Options\n * @returns All preference topics in the organization\n */\nexport async function fetchAllPreferenceTopics(\n client: GraphQLClient,\n options: {\n /** Logger instance */\n logger: Logger;\n },\n): Promise<PreferenceTopic[]> {\n const { logger } = options;\n const preferenceTopics: PreferenceTopic[] = [];\n let offset = 0;\n\n let shouldContinue = false;\n do {\n const {\n preferenceTopics: { nodes },\n } = await makeGraphQLRequest<{\n /** Preference topics */\n preferenceTopics: { /** List */ nodes: PreferenceTopic[] };\n }>(client, PREFERENCE_TOPICS, {\n logger,\n variables: { first: PAGE_SIZE, offset },\n });\n preferenceTopics.push(...nodes);\n offset += PAGE_SIZE;\n shouldContinue = nodes.length === PAGE_SIZE;\n } while (shouldContinue);\n\n return preferenceTopics.sort((a, b) =>\n `${a.slug}:${a.purpose.trackingType}`.localeCompare(`${b.slug}:${b.purpose.trackingType}`),\n );\n}\n","import type { Logger } from '@transcend-io/utils';\nimport type { GraphQLClient } from 'graphql-request';\n\nimport { type PreferenceTopic, fetchAllPreferenceTopics } from './fetchAllPreferenceTopics.js';\nimport { type Purpose, fetchAllPurposes } from './fetchAllPurposes.js';\n\nexport interface PurposeWithPreferences extends Purpose {\n /** Topics */\n topics: PreferenceTopic[];\n}\n\n/**\n * Fetch all purposes and preferences\n *\n * @param client - GraphQL client\n * @param options - Options\n * @returns List of purposes with their preference topics\n */\nexport async function fetchAllPurposesAndPreferences(\n client: GraphQLClient,\n options: { /** Logger instance */ logger: Logger },\n): Promise<PurposeWithPreferences[]> {\n const [purposes, topics] = await Promise.all([\n fetchAllPurposes(client, options),\n fetchAllPreferenceTopics(client, options),\n ]);\n\n return purposes.map((purpose) => ({\n ...purpose,\n topics: topics.filter((topic) => topic.purpose.trackingType === purpose.trackingType),\n }));\n}\n","import { parse, type DocumentNode } from 'graphql';\nimport { gql } from 'graphql-request';\n\nexport const CREATE_PREFERENCE_ACCESS_TOKENS: DocumentNode = parse(gql`\n mutation TranscendCliCreatePreferenceAccessTokens($input: CreatePrivacyCenterAccessTokensInput!) {\n createPrivacyCenterAccessTokens(input: $input) {\n nodes {\n token\n }\n }\n }\n`);\n","import type { SombraStandardScope } from '@transcend-io/privacy-types';\nimport { map, type Logger } from '@transcend-io/utils';\nimport type { GraphQLClient } from 'graphql-request';\nimport { chunk } from 'lodash-es';\n\nimport { makeGraphQLRequest } from '../api/makeGraphQLRequest.js';\nimport { CREATE_PREFERENCE_ACCESS_TOKENS } from './gqls/preferenceAccessTokens.js';\n\nexport interface PreferenceAccessTokenInput {\n /** Slug of data subject to authenticate as */\n subjectType: string;\n /** Scopes to grant */\n scopes: SombraStandardScope[];\n /** Expiration time in seconds */\n expiresIn?: number;\n /** Email address of user */\n email: string;\n /** Core identifier for the user */\n coreIdentifier?: string;\n}\n\nexport interface PreferenceAccessTokenInputWithIndex extends PreferenceAccessTokenInput {\n /** Index of the input record */\n index?: number;\n}\n\nconst MAX_BATCH_SIZE = 50;\n\n/**\n * Create preference access tokens for a single page of identifiers.\n *\n * @param client - GraphQL client\n * @param records - Inputs to sign\n * @param logger - Logger\n * @returns list of access tokens\n */\nasync function createPreferenceAccessTokensPage(\n client: GraphQLClient,\n records: PreferenceAccessTokenInput[],\n logger: Logger,\n): Promise<string[]> {\n const {\n createPrivacyCenterAccessTokens: { nodes },\n } = await makeGraphQLRequest<{\n /** createPrivacyCenterAccessTokens mutation */\n createPrivacyCenterAccessTokens: {\n /** Nodes */\n nodes: { /** Token */ token: string }[];\n };\n }>(client, CREATE_PREFERENCE_ACCESS_TOKENS, {\n logger,\n variables: { input: { records } },\n });\n return nodes.map((node) => node.token);\n}\n\n/**\n * Create preference access tokens for the given identifiers.\n *\n * @see https://docs.transcend.io/docs/articles/preference-management/access-links\n * @param client - GraphQL client\n * @param options - Options\n * @returns list of access tokens/input identifiers\n */\nexport async function createPreferenceAccessTokens(\n client: GraphQLClient,\n options: {\n /** Records to create tokens for */\n records: PreferenceAccessTokenInputWithIndex[];\n /** Logger instance */\n logger: Logger;\n /** Optional progress emitter */\n emitProgress?: (progress: number) => void;\n /** Number of concurrent requests to make (default: 10) */\n concurrency?: number;\n },\n): Promise<\n {\n /** Identifier for the record */\n input: PreferenceAccessTokenInputWithIndex;\n /** Access token */\n accessToken: string;\n }[]\n> {\n const { records, logger, emitProgress, concurrency = 10 } = options;\n\n let completed = 0;\n emitProgress?.(0);\n\n const results: {\n /** Identifier for the record */\n input: PreferenceAccessTokenInput;\n /** Access token */\n accessToken: string;\n }[] = [];\n\n await map(\n chunk(records, MAX_BATCH_SIZE),\n async (chunkedRecords) => {\n const tokens = await createPreferenceAccessTokensPage(\n client,\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n chunkedRecords.map(({ index, ...rest }) => rest),\n logger,\n );\n const mappedResults = tokens.map((token, idx) => ({\n input: chunkedRecords[idx]!,\n accessToken: token,\n }));\n results.push(...mappedResults);\n completed += chunkedRecords.length;\n emitProgress?.(completed);\n },\n { concurrency },\n );\n\n return results;\n}\n","import { describePackageName } from '@transcend-io/utils';\n\nexport interface MonorepoPackageDefinition {\n directory: string;\n displayName: string;\n packageName: string;\n}\n\nexport function createMonorepoPackageDefinition(\n name: string,\n directory: string,\n): MonorepoPackageDefinition {\n const packageNameParts = describePackageName(name);\n\n return {\n directory,\n displayName: packageNameParts.displayName,\n packageName: `@transcend-io/${packageNameParts.slug}`,\n };\n}\n\nexport * from './api/index.js';\nexport * from './data-inventory/index.js';\nexport * from './preference-management/index.js';\n"],"mappings":";;;;;;;;;;;;;;AAUA,SAAgB,mCACd,cACA,SACA,SACe;AACf,QAAO,IAAI,cAAc,GAAG,aAAa,WAAW,EAClD,SAAS;EACP,GAAG;EACH,GAAI,UAAU,EAAE,SAAS,GAAG,EAAE;EAC/B,EACF,CAAC;;;;;;;;;;AAWJ,SAAgB,4BACd,cACA,MACA,SACe;AACf,QAAO,mCACL,cACA,EAAE,eAAe,UAAU,QAAQ,EACnC,QACD;;;;ACrCH,MAAM,sBAAsB;AAE5B,MAAM,eAAe;CACnB;CACA;CACA;CACA;CACA;CACD;;;;;;;;;AAUD,eAAsB,mBACpB,QACA,UACA,SAUY;CACZ,MAAM,EAAE,WAAW,QAAQ,gBAAgB,aAAa,wBAAwB;CAEhF,IAAI,aAAa;AAEjB,QAAO,KACL,KAAI;AAEF,SADe,MAAM,OAAO,QAAQ,UAAU,WAAW,eAAe;UAGjE,KAAU;AACjB,MAAI,IAAI,SAAS,SAAS,qBAAqB,CAC7C,OAAM,IAAI,MACR,uLAGD;AAGH,MAAI,aAAa,MAAM,QAAQ,IAAI,SAAS,SAAS,IAAI,CAAC,CACxD,OAAM;AAGR,MAAI,IAAI,SAAS,WAAW,kCAAkC,EAAE;GAC9D,MAAM,mBAAmB,IAAI,UAAU,SAAS,IAAI,oBAAoB;GACxE,MAAM,YAAY,mBACd,IAAI,KAAK,iBAAiB,CAAC,SAAS,oBAAG,IAAI,MAAM,EAAC,SAAS,GAAG,MAC9D,MAAO;AACX,UAAO,KAAK,wBAAwB,IAAI,QAAQ,iBAAiB,UAAU,IAAI;AAC/E,SAAM,aAAa,UAAU;;AAG/B,MAAI,cAAc,WAChB,OAAM;AAER,gBAAc;AACd,SAAO,KAAK,4BAA4B,WAAW,KAAK,WAAW,KAAK,IAAI,UAAU;;;;;ACnE5F,MAAa,eAA6B,MAAM,GAAG;;;;;;;;EAQjD;;;;;;;;;;;;ACKF,eAAsB,wBACpB,cACA,iBACA,SAQc;CACd,MAAM,EAAE,QAAQ,cAAc,cAAc;CAG5C,MAAM,EAAE,iBAAiB,MAAM,mBADhB,4BAA4B,cAAc,gBAAgB,EAU9D,cAAc,EAAE,QAAQ,CAAC;CAEpC,MAAM,EAAE,gBAAgB,aAAa;CACrC,MAAM,cAAc,aAAa;AAEjC,KACE,CAAC,aACD,CACE,8CACA,gDACD,CAAC,SAAS,YAAY,CAEvB,OAAM,IAAI,MACR,qOAGD;AAEH,QAAO,KAAK,iBAAiB,cAAc;AAE3C,QAAO,IAAI,OAAO;EAChB,WAAW;EACX,SAAS;GACP,eAAe,UAAU;GACzB,GAAI,eAAe,EAAE,0BAA0B,UAAU,gBAAgB,GAAG,EAAE;GAC/E;EACF,CAAC;;;;AC/DJ,MAAa,cAA4B,MAAM,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA+BhD;;;ACEF,MAAMA,cAAY;;;;;;;;AASlB,eAAsB,oBACpB,QACA,SACuB;CACvB,MAAM,EAAE,WAAW;CACnB,MAAM,cAA4B,EAAE;CACpC,IAAI,SAAS;CAEb,IAAI,iBAAiB;AACrB,IAAG;EACD,MAAM,EACJ,aAAa,EAAE,YACb,MAAM,mBAGP,QAAQ,aAAa;GACtB;GACA,WAAW;IAAE,OAAOA;IAAW;IAAQ;GACxC,CAAC;AACF,cAAY,KAAK,GAAG,MAAM;AAC1B,YAAUA;AACV,mBAAiB,MAAM,WAAWA;UAC3B;AAET,QAAO,YAAY,MAAM,GAAG,MAAM,EAAE,KAAK,cAAc,EAAE,KAAK,CAAC;;;;AClEjE,MAAa,WAAyB,MAAM,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;EA2B7C;;;ACWF,MAAMC,cAAY;;;;;;;;AASlB,eAAsB,iBACpB,QACA,SAMoB;CACpB,MAAM,EAAE,QAAQ,iBAAiB,UAAU;CAC3C,MAAM,WAAsB,EAAE;CAC9B,IAAI,SAAS;CAEb,IAAI,iBAAiB;AACrB,IAAG;EACD,MAAM,EACJ,UAAU,EAAE,YACV,MAAM,mBAGP,QAAQ,UAAU;GACnB;GACA,WAAW;IAAE,OAAOA;IAAW;IAAQ,OAAO,EAAE,gBAAgB;IAAE;GACnE,CAAC;AACF,WAAS,KAAK,GAAG,MAAM;AACvB,YAAUA;AACV,mBAAiB,MAAM,WAAWA;UAC3B;AAET,QAAO,SAAS,MAAM,GAAG,MAAM,EAAE,aAAa,cAAc,EAAE,aAAa,CAAC;;;;AC5E9E,MAAa,oBAAkC,MAAM,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAkCtD;;;ACJF,MAAM,YAAY;;;;;;;;AASlB,eAAsB,yBACpB,QACA,SAI4B;CAC5B,MAAM,EAAE,WAAW;CACnB,MAAM,mBAAsC,EAAE;CAC9C,IAAI,SAAS;CAEb,IAAI,iBAAiB;AACrB,IAAG;EACD,MAAM,EACJ,kBAAkB,EAAE,YAClB,MAAM,mBAGP,QAAQ,mBAAmB;GAC5B;GACA,WAAW;IAAE,OAAO;IAAW;IAAQ;GACxC,CAAC;AACF,mBAAiB,KAAK,GAAG,MAAM;AAC/B,YAAU;AACV,mBAAiB,MAAM,WAAW;UAC3B;AAET,QAAO,iBAAiB,MAAM,GAAG,MAC/B,GAAG,EAAE,KAAK,GAAG,EAAE,QAAQ,eAAe,cAAc,GAAG,EAAE,KAAK,GAAG,EAAE,QAAQ,eAAe,CAC3F;;;;;;;;;;;ACrDH,eAAsB,+BACpB,QACA,SACmC;CACnC,MAAM,CAAC,UAAU,UAAU,MAAM,QAAQ,IAAI,CAC3C,iBAAiB,QAAQ,QAAQ,EACjC,yBAAyB,QAAQ,QAAQ,CAC1C,CAAC;AAEF,QAAO,SAAS,KAAK,aAAa;EAChC,GAAG;EACH,QAAQ,OAAO,QAAQ,UAAU,MAAM,QAAQ,iBAAiB,QAAQ,aAAa;EACtF,EAAE;;;;AC3BL,MAAa,kCAAgD,MAAM,GAAG;;;;;;;;EAQpE;;;ACeF,MAAM,iBAAiB;;;;;;;;;AAUvB,eAAe,iCACb,QACA,SACA,QACmB;CACnB,MAAM,EACJ,iCAAiC,EAAE,YACjC,MAAM,mBAMP,QAAQ,iCAAiC;EAC1C;EACA,WAAW,EAAE,OAAO,EAAE,SAAS,EAAE;EAClC,CAAC;AACF,QAAO,MAAM,KAAK,SAAS,KAAK,MAAM;;;;;;;;;;AAWxC,eAAsB,6BACpB,QACA,SAiBA;CACA,MAAM,EAAE,SAAS,QAAQ,cAAc,cAAc,OAAO;CAE5D,IAAI,YAAY;AAChB,gBAAe,EAAE;CAEjB,MAAM,UAKA,EAAE;AAER,OAAM,IACJ,MAAM,SAAS,eAAe,EAC9B,OAAO,mBAAmB;EAOxB,MAAM,iBANS,MAAM,iCACnB,QAEA,eAAe,KAAK,EAAE,OAAO,GAAG,WAAW,KAAK,EAChD,OACD,EAC4B,KAAK,OAAO,SAAS;GAChD,OAAO,eAAe;GACtB,aAAa;GACd,EAAE;AACH,UAAQ,KAAK,GAAG,cAAc;AAC9B,eAAa,eAAe;AAC5B,iBAAe,UAAU;IAE3B,EAAE,aAAa,CAChB;AAED,QAAO;;;;AC5GT,SAAgB,gCACd,MACA,WAC2B;CAC3B,MAAM,mBAAmB,oBAAoB,KAAK;AAElD,QAAO;EACL;EACA,aAAa,iBAAiB;EAC9B,aAAa,iBAAiB,iBAAiB;EAChD"}
package/package.json ADDED
@@ -0,0 +1,48 @@
1
+ {
2
+ "name": "@transcend-io/sdk",
3
+ "version": "0.0.0",
4
+ "description": "Transcend SDK — shared GraphQL/REST API clients and preference management utilities.",
5
+ "license": "Apache-2.0",
6
+ "files": [
7
+ "dist"
8
+ ],
9
+ "type": "module",
10
+ "sideEffects": false,
11
+ "types": "./dist/index.d.mts",
12
+ "exports": {
13
+ ".": {
14
+ "@transcend-io/source": "./src/index.ts",
15
+ "types": "./dist/index.d.mts",
16
+ "default": "./dist/index.mjs"
17
+ }
18
+ },
19
+ "publishConfig": {
20
+ "access": "public"
21
+ },
22
+ "scripts": {
23
+ "build": "tsdown",
24
+ "typecheck": "tsc -p tsconfig.json --noEmit",
25
+ "test": "vitest run",
26
+ "check-exports": "attw --pack . --ignore-rules cjs-resolves-to-esm"
27
+ },
28
+ "dependencies": {
29
+ "@transcend-io/airgap.js-types": "^12.16.0",
30
+ "@transcend-io/privacy-types": "workspace:*",
31
+ "@transcend-io/utils": "workspace:*",
32
+ "got": "^11.8.5",
33
+ "graphql": "^16.6.0",
34
+ "graphql-request": "^5.0.0",
35
+ "lodash-es": "^4.17.21"
36
+ },
37
+ "devDependencies": {
38
+ "@arethetypeswrong/cli": "catalog:",
39
+ "@types/lodash-es": "^4.17.12",
40
+ "@types/node": "catalog:",
41
+ "tsdown": "catalog:",
42
+ "typescript": "catalog:",
43
+ "vitest": "catalog:"
44
+ },
45
+ "engines": {
46
+ "node": ">=22.0.0"
47
+ }
48
+ }