lytx 0.3.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.
- package/.env.example +37 -0
- package/README.md +486 -0
- package/alchemy.run.ts +155 -0
- package/cli/bootstrap-admin.ts +284 -0
- package/cli/deploy-staging.ts +692 -0
- package/cli/import-events.ts +628 -0
- package/cli/import-sites.ts +518 -0
- package/cli/index.ts +609 -0
- package/cli/init-db.ts +269 -0
- package/cli/migrate-to-durable-objects.ts +564 -0
- package/cli/migration-worker.ts +300 -0
- package/cli/performance-test.ts +588 -0
- package/cli/pg/client.ts +4 -0
- package/cli/pg/new-site.ts +153 -0
- package/cli/rollback-durable-objects.ts +622 -0
- package/cli/seed-data.ts +459 -0
- package/cli/setup.js +18 -0
- package/cli/setup.ts +463 -0
- package/cli/validate-migration.ts +200 -0
- package/cli/wrangler-migration.jsonc +28 -0
- package/db/adapter.ts +166 -0
- package/db/analytics_engine/client.ts +0 -0
- package/db/analytics_engine/sites.ts +0 -0
- package/db/client.ts +16 -0
- package/db/d1/client.ts +8 -0
- package/db/d1/drizzle.config.ts +35 -0
- package/db/d1/migrations/0000_true_maelstrom.sql +165 -0
- package/db/d1/migrations/0001_wonderful_bloodaxe.sql +12 -0
- package/db/d1/migrations/0002_late_frightful_four.sql +1 -0
- package/db/d1/migrations/0003_cuddly_obadiah_stane.sql +16 -0
- package/db/d1/migrations/0004_mute_stardust.sql +1 -0
- package/db/d1/migrations/0005_awesome_silvermane.sql +3 -0
- package/db/d1/migrations/0006_volatile_shriek.sql +2 -0
- package/db/d1/migrations/0007_superb_lila_cheney.sql +1 -0
- package/db/d1/migrations/0008_bitter_longshot.sql +17 -0
- package/db/d1/migrations/0009_wonderful_madame_masque.sql +28 -0
- package/db/d1/migrations/meta/0000_snapshot.json +1112 -0
- package/db/d1/migrations/meta/0001_snapshot.json +1187 -0
- package/db/d1/migrations/meta/0002_snapshot.json +1194 -0
- package/db/d1/migrations/meta/0003_snapshot.json +1296 -0
- package/db/d1/migrations/meta/0004_snapshot.json +1303 -0
- package/db/d1/migrations/meta/0005_snapshot.json +1325 -0
- package/db/d1/migrations/meta/0006_snapshot.json +1339 -0
- package/db/d1/migrations/meta/0007_snapshot.json +1347 -0
- package/db/d1/migrations/meta/0008_snapshot.json +1464 -0
- package/db/d1/migrations/meta/0009_snapshot.json +1648 -0
- package/db/d1/migrations/meta/_journal.json +76 -0
- package/db/d1/schema.ts +407 -0
- package/db/d1/sites.ts +374 -0
- package/db/d1/teamAiUsage.ts +101 -0
- package/db/d1/teams.ts +127 -0
- package/db/durable/drizzle.config.ts +8 -0
- package/db/durable/durableObjectClient.ts +480 -0
- package/db/durable/events.ts +100 -0
- package/db/durable/migrations/0000_fair_bucky.sql +38 -0
- package/db/durable/migrations/meta/0000_snapshot.json +278 -0
- package/db/durable/migrations/meta/_journal.json +13 -0
- package/db/durable/migrations/migrations.js +10 -0
- package/db/durable/schema.ts +5 -0
- package/db/durable/siteDurableObject.ts +1352 -0
- package/db/durable/types.ts +53 -0
- package/db/postgres/client.ts +13 -0
- package/db/postgres/drizzle.config.ts +12 -0
- package/db/postgres/migrations/0000_brainy_sprite.sql +116 -0
- package/db/postgres/migrations/meta/0000_snapshot.json +681 -0
- package/db/postgres/migrations/meta/_journal.json +13 -0
- package/db/postgres/schema.ts +145 -0
- package/db/postgres/sites.ts +118 -0
- package/db/tranformReports.ts +595 -0
- package/db/types.ts +55 -0
- package/endpoints/api_worker.tsx +1854 -0
- package/endpoints/site_do_worker.ts +11 -0
- package/index.d.ts +63 -0
- package/index.ts +83 -0
- package/lib/auth.ts +279 -0
- package/lib/geojson/world_countries.json +45307 -0
- package/lib/random_name.ts +41 -0
- package/lib/sendMail.ts +252 -0
- package/package.json +142 -0
- package/public/favicon.ico +0 -0
- package/public/images/android-chrome-192x192.png +0 -0
- package/public/images/android-chrome-512x512.png +0 -0
- package/public/images/apple-touch-icon.png +0 -0
- package/public/images/favicon-16x16.png +0 -0
- package/public/images/favicon-32x32.png +0 -0
- package/public/images/lytx_dark_dashboard.png +0 -0
- package/public/images/lytx_light_dashboard.png +0 -0
- package/public/images/safari-pinned-tab.svg +4 -0
- package/public/logo.png +0 -0
- package/public/site.webmanifest +26 -0
- package/public/sw.js +107 -0
- package/src/Document.tsx +86 -0
- package/src/api/ai_api.ts +1156 -0
- package/src/api/authMiddleware.ts +45 -0
- package/src/api/auth_api.ts +465 -0
- package/src/api/event_labels_api.ts +193 -0
- package/src/api/events_api.ts +210 -0
- package/src/api/queueWorker.ts +303 -0
- package/src/api/reports_api.ts +278 -0
- package/src/api/seed_api.ts +288 -0
- package/src/api/sites_api.ts +904 -0
- package/src/api/tag_api.ts +458 -0
- package/src/api/tag_api_v2.ts +289 -0
- package/src/api/team_api.ts +456 -0
- package/src/app/Dashboard.tsx +1339 -0
- package/src/app/Events.tsx +974 -0
- package/src/app/Explore.tsx +312 -0
- package/src/app/Layout.tsx +58 -0
- package/src/app/Settings.tsx +1302 -0
- package/src/app/components/DashboardCard.tsx +118 -0
- package/src/app/components/EditableCell.tsx +123 -0
- package/src/app/components/EventForm.tsx +93 -0
- package/src/app/components/MarketingFooter.tsx +49 -0
- package/src/app/components/MarketingNav.tsx +150 -0
- package/src/app/components/Nav.tsx +755 -0
- package/src/app/components/NewSiteSetup.tsx +298 -0
- package/src/app/components/SQLEditor.tsx +740 -0
- package/src/app/components/SiteSelector.tsx +126 -0
- package/src/app/components/SiteTag.tsx +42 -0
- package/src/app/components/SiteTagInstallCard.tsx +241 -0
- package/src/app/components/WorldMapCard.tsx +337 -0
- package/src/app/components/charts/ChartComponents.tsx +1481 -0
- package/src/app/components/charts/EventFunnel.tsx +45 -0
- package/src/app/components/charts/EventSummary.tsx +194 -0
- package/src/app/components/charts/SankeyFlows.tsx +72 -0
- package/src/app/components/marketing/CheckIcon.tsx +16 -0
- package/src/app/components/marketing/MarketingLayout.tsx +23 -0
- package/src/app/components/marketing/SectionHeading.tsx +35 -0
- package/src/app/components/reports/AskAiWorkspace.tsx +371 -0
- package/src/app/components/reports/CreateReportStarter.tsx +74 -0
- package/src/app/components/reports/DashboardRouteFiltersContext.tsx +14 -0
- package/src/app/components/reports/DashboardToolbar.tsx +154 -0
- package/src/app/components/reports/DashboardWorkspaceLayout.tsx +63 -0
- package/src/app/components/reports/DashboardWorkspaceShell.tsx +118 -0
- package/src/app/components/reports/ReportBuilderWorkspace.tsx +76 -0
- package/src/app/components/reports/custom/CustomReportBuilderPage.tsx +1667 -0
- package/src/app/components/reports/custom/ReportWidgetChart.tsx +297 -0
- package/src/app/components/reports/custom/buildWidgetSql.ts +151 -0
- package/src/app/components/reports/custom/chartPalettes.ts +18 -0
- package/src/app/components/reports/custom/types.ts +50 -0
- package/src/app/components/reports/reportBuilderMenuItems.ts +17 -0
- package/src/app/components/reports/useDashboardToolbarControls.tsx +235 -0
- package/src/app/components/ui/AlertBanner.tsx +101 -0
- package/src/app/components/ui/Button.tsx +55 -0
- package/src/app/components/ui/Card.tsx +80 -0
- package/src/app/components/ui/Input.tsx +72 -0
- package/src/app/components/ui/Link.tsx +23 -0
- package/src/app/components/ui/ReportBuilderMenu.tsx +246 -0
- package/src/app/components/ui/ThemeToggle.tsx +54 -0
- package/src/app/constants.ts +6 -0
- package/src/app/headers.ts +33 -0
- package/src/app/providers/AuthProvider.tsx +189 -0
- package/src/app/providers/ClientProviders.tsx +18 -0
- package/src/app/providers/QueryProvider.tsx +23 -0
- package/src/app/providers/ThemeProvider.tsx +88 -0
- package/src/app/utils/chartThemes.ts +146 -0
- package/src/app/utils/keybinds.ts +96 -0
- package/src/app/utils/media.tsx +24 -0
- package/src/client.tsx +114 -0
- package/src/config/createLytxAppConfig.ts +252 -0
- package/src/config/resourceNames.ts +88 -0
- package/src/db/index.ts +67 -0
- package/src/index.css +285 -0
- package/src/lib/featureFlags.ts +69 -0
- package/src/pages/GetStarted.tsx +290 -0
- package/src/pages/Home.tsx +268 -0
- package/src/pages/Login.tsx +283 -0
- package/src/pages/PrivacyPolicy.tsx +120 -0
- package/src/pages/Signup.tsx +267 -0
- package/src/pages/TermsOfService.tsx +126 -0
- package/src/pages/VerifyEmail.tsx +56 -0
- package/src/session/durableObject.ts +7 -0
- package/src/session/siteSchema.ts +86 -0
- package/src/session/types.ts +36 -0
- package/src/templates/README.md +80 -0
- package/src/templates/cleanFunctions.js +44 -0
- package/src/templates/embedFunctions.js +52 -0
- package/src/templates/lytx-shared.ts +662 -0
- package/src/templates/lytxpixel-core.ts +144 -0
- package/src/templates/lytxpixel.ts +267 -0
- package/src/templates/lytxpixelBrowser.js +634 -0
- package/src/templates/lytxpixelBrowser.mjs +634 -0
- package/src/templates/parseData.js +12 -0
- package/src/templates/script.ts +31 -0
- package/src/templates/template.tsx +50 -0
- package/src/templates/test.js +3 -0
- package/src/templates/trackWebEvents.ts +177 -0
- package/src/templates/vendors/clickcease.ts +8 -0
- package/src/templates/vendors/google.ts +174 -0
- package/src/templates/vendors/linkedin.ts +23 -0
- package/src/templates/vendors/meta.ts +56 -0
- package/src/templates/vendors/quantcast.ts +22 -0
- package/src/templates/vendors/simplfi.ts +7 -0
- package/src/types/app-context.ts +16 -0
- package/src/utilities/dashboardParams.ts +188 -0
- package/src/utilities/dashboardQueries.ts +537 -0
- package/src/utilities/dashboardTransforms.ts +167 -0
- package/src/utilities/dataValidation.ts +414 -0
- package/src/utilities/detector.ts +73 -0
- package/src/utilities/encrypt.ts +103 -0
- package/src/utilities/index.ts +13 -0
- package/src/utilities/parser.ts +117 -0
- package/src/utilities/performanceMonitoring.ts +570 -0
- package/src/utilities/route_interuptors.ts +24 -0
- package/src/worker.tsx +675 -0
- package/tsconfig.json +78 -0
- package/types/env.d.ts +16 -0
- package/types/rw.d.ts +7 -0
- package/types/shims.d.ts +53 -0
- package/types/vite.d.ts +19 -0
- package/vite/vite-plugin-pixel-bundle.ts +126 -0
- package/vite.config.ts +53 -0
- package/worker-configuration.d.ts +8401 -0
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generate a new encryption key (run this locally once, not in production)
|
|
3
|
+
* @returns Base64 encoded encryption key
|
|
4
|
+
*/
|
|
5
|
+
export async function generateEncryptionKey(): Promise<string> {
|
|
6
|
+
const key = await crypto.subtle.generateKey(
|
|
7
|
+
{ name: "AES-GCM", length: 256 },
|
|
8
|
+
true,
|
|
9
|
+
["encrypt", "decrypt"]
|
|
10
|
+
);
|
|
11
|
+
|
|
12
|
+
const exportedKey = await crypto.subtle.exportKey("raw", key);
|
|
13
|
+
return btoa(String.fromCharCode(...new Uint8Array(exportedKey)));
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Import an encryption key from base64 format
|
|
19
|
+
* @param keyBase64 Base64 encoded encryption key
|
|
20
|
+
* @returns CryptoKey object for encryption/decryption
|
|
21
|
+
*/
|
|
22
|
+
export async function getEncryptionKey(keyBase64: string): Promise<CryptoKey> {
|
|
23
|
+
const keyBytes = Uint8Array.from(atob(keyBase64), c => c.charCodeAt(0));
|
|
24
|
+
return await crypto.subtle.importKey(
|
|
25
|
+
"raw",
|
|
26
|
+
keyBytes,
|
|
27
|
+
{ name: "AES-GCM", length: 256 },
|
|
28
|
+
false,
|
|
29
|
+
["encrypt", "decrypt"]
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Encrypt a string value
|
|
36
|
+
* @param value The string to encrypt
|
|
37
|
+
* @param keyBase64 Base64 encoded encryption key
|
|
38
|
+
* @returns Object containing encrypted value and initialization vector
|
|
39
|
+
*/
|
|
40
|
+
export async function encrypt(value: string, keyBase64: string): Promise<{
|
|
41
|
+
encryptedValue: string;
|
|
42
|
+
iv: string;
|
|
43
|
+
}> {
|
|
44
|
+
// Create a random initialization vector
|
|
45
|
+
const iv = crypto.getRandomValues(new Uint8Array(12));
|
|
46
|
+
|
|
47
|
+
// Get the key
|
|
48
|
+
const key = await getEncryptionKey(keyBase64);
|
|
49
|
+
|
|
50
|
+
// Encode the string as bytes
|
|
51
|
+
const encoder = new TextEncoder();
|
|
52
|
+
const valueBytes = encoder.encode(value);
|
|
53
|
+
|
|
54
|
+
// Encrypt the value
|
|
55
|
+
const encryptedBytes = await crypto.subtle.encrypt(
|
|
56
|
+
{ name: "AES-GCM", iv },
|
|
57
|
+
key,
|
|
58
|
+
valueBytes
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
// Convert to base64 for storage
|
|
62
|
+
const encryptedValue = btoa(String.fromCharCode(...new Uint8Array(encryptedBytes)));
|
|
63
|
+
const ivBase64 = btoa(String.fromCharCode(...iv));
|
|
64
|
+
|
|
65
|
+
return { encryptedValue, iv: ivBase64 };
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Decrypt an encrypted string value
|
|
71
|
+
* @param encryptedValue Base64 encoded encrypted value
|
|
72
|
+
* @param ivBase64 Base64 encoded initialization vector
|
|
73
|
+
* @param keyBase64 Base64 encoded encryption key
|
|
74
|
+
* @returns The decrypted string
|
|
75
|
+
*/
|
|
76
|
+
export async function decrypt(
|
|
77
|
+
encryptedValue: string,
|
|
78
|
+
ivBase64: string,
|
|
79
|
+
keyBase64: string
|
|
80
|
+
): Promise<string> {
|
|
81
|
+
try {
|
|
82
|
+
// Convert from base64
|
|
83
|
+
const encryptedBytes = Uint8Array.from(atob(encryptedValue), c => c.charCodeAt(0));
|
|
84
|
+
const iv = Uint8Array.from(atob(ivBase64), c => c.charCodeAt(0));
|
|
85
|
+
|
|
86
|
+
// Get the key
|
|
87
|
+
const key = await getEncryptionKey(keyBase64);
|
|
88
|
+
|
|
89
|
+
// Decrypt
|
|
90
|
+
const decryptedBytes = await crypto.subtle.decrypt(
|
|
91
|
+
{ name: "AES-GCM", iv },
|
|
92
|
+
key,
|
|
93
|
+
encryptedBytes
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
// Convert back to string
|
|
97
|
+
const decoder = new TextDecoder();
|
|
98
|
+
return decoder.decode(decryptedBytes);
|
|
99
|
+
} catch (error) {
|
|
100
|
+
console.error("Decryption failed:", error);
|
|
101
|
+
throw new Error("Failed to decrypt value. The data may be corrupted or the key is incorrect.", { cause: error });
|
|
102
|
+
}
|
|
103
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
//import { crypto } from "@cloudflare/workers-types";
|
|
2
|
+
|
|
3
|
+
export async function hashIpAddress(ipAddress:string, salt:string) {
|
|
4
|
+
const encoder = new TextEncoder();
|
|
5
|
+
const data = encoder.encode(ipAddress + salt); // Combine IP address and salt
|
|
6
|
+
const hashBuffer = await crypto.subtle.digest('SHA-256', data);
|
|
7
|
+
const hashArray = Array.from(new Uint8Array(hashBuffer));
|
|
8
|
+
const hashHex = hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
|
|
9
|
+
return hashHex;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
//crypto
|
|
13
|
+
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { PageEvent, parseData } from "@/templates/lytxpixel";
|
|
2
|
+
import { trackEvents } from "@/templates/trackWebEvents";
|
|
3
|
+
const dataVariableName = "lytxDataLayer" as const;
|
|
4
|
+
|
|
5
|
+
// Comprehensive function cleaner for build artifacts
|
|
6
|
+
function cleanFunctionForEmbedding(func: Function): string {
|
|
7
|
+
let source = func.toString();
|
|
8
|
+
|
|
9
|
+
// Remove all variations of __name and @__PURE__ annotations
|
|
10
|
+
source = source
|
|
11
|
+
// Remove standalone @__PURE__ comments
|
|
12
|
+
.replace(/\/\*\s*@__PURE__\s*\*\/\s*/g, '')
|
|
13
|
+
// Remove __name calls with various patterns
|
|
14
|
+
.replace(/__name\s*\([^)]*\)\s*[,;]?\s*/g, '')
|
|
15
|
+
// Remove combined patterns like "= /* @__PURE__ */ __name("
|
|
16
|
+
.replace(/=\s*\/\*\s*@__PURE__\s*\*\/\s*__name\s*\([^,)]*,\s*[^)]*\)/g, '= ')
|
|
17
|
+
// Remove const declarations with __name
|
|
18
|
+
.replace(/const\s+(\w+)\s*=\s*\/\*\s*@__PURE__\s*\*\/\s*__name\s*\([^,)]*,\s*[^)]*\)/g, 'const $1 = ')
|
|
19
|
+
// Clean up function expressions
|
|
20
|
+
.replace(/function\s*\(\)\s*\{\s*return\s*([^}]+)\s*\}\s*\(\)/g, '$1')
|
|
21
|
+
// Remove any remaining __name references
|
|
22
|
+
.replace(/__name/g, '')
|
|
23
|
+
// Clean up extra commas and semicolons
|
|
24
|
+
.replace(/,\s*[,;]/g, ',')
|
|
25
|
+
.replace(/;\s*;/g, ';')
|
|
26
|
+
// Normalize whitespace
|
|
27
|
+
.replace(/\s+/g, ' ')
|
|
28
|
+
.trim();
|
|
29
|
+
|
|
30
|
+
return source;
|
|
31
|
+
}
|
|
32
|
+
type TagConfig = { site: string, tag: string, track_web_events: boolean, gdpr: boolean };
|
|
33
|
+
type QueryParams = {
|
|
34
|
+
[key: string]: string[];
|
|
35
|
+
};
|
|
36
|
+
type DataVariableName = typeof dataVariableName;
|
|
37
|
+
|
|
38
|
+
type ScriptConfig = { config: TagConfig, queryParamsStr?: string, data: PageEvent[], dataVariableName: DataVariableName };
|
|
39
|
+
//TODO fix types for config and queryParamsStr
|
|
40
|
+
export function generateScript(conf: ScriptConfig) {
|
|
41
|
+
const { config, queryParamsStr, data, dataVariableName } = conf;
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
//TODO check these
|
|
45
|
+
const dataObjects = data.map(item => {
|
|
46
|
+
return `
|
|
47
|
+
{
|
|
48
|
+
event_name: ${JSON.stringify(item.event_name)},
|
|
49
|
+
condition: ${JSON.stringify(item.condition)},
|
|
50
|
+
data_passback: ${JSON.stringify(item.data_passback)},
|
|
51
|
+
parameters: ${JSON.stringify(item.parameters)},
|
|
52
|
+
paramConfig: ${JSON.stringify(item.paramConfig)},
|
|
53
|
+
query_parameters: ${JSON.stringify(item.query_parameters)},
|
|
54
|
+
customScript: ${JSON.stringify(item.customScript)},
|
|
55
|
+
rules: ${JSON.stringify(item.rules)},
|
|
56
|
+
Notes: ${JSON.stringify(item.Notes)}
|
|
57
|
+
}
|
|
58
|
+
`;
|
|
59
|
+
}).join(',');
|
|
60
|
+
|
|
61
|
+
//part to impor
|
|
62
|
+
|
|
63
|
+
//!dont forget to check for config gdp and change data
|
|
64
|
+
|
|
65
|
+
//var config = ${JSON.stringify(config)};
|
|
66
|
+
//var queryParamsStr = "${queryParamsStr}";
|
|
67
|
+
const jsTemplate = `
|
|
68
|
+
(function() {
|
|
69
|
+
const dataVariableName = [${dataObjects}];
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
if(window.${dataVariableName}){
|
|
73
|
+
window.${dataVariableName}.push(
|
|
74
|
+
{site:"${config.site}",tag:"${config.tag}",events:${dataVariableName},tracked:[]}
|
|
75
|
+
)
|
|
76
|
+
}else{
|
|
77
|
+
window.${dataVariableName} = [
|
|
78
|
+
{site:"${config.site}",tag:"${config.tag}",events:${dataVariableName},tracked:[]}
|
|
79
|
+
]
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
//parseData
|
|
83
|
+
//trackEvents
|
|
84
|
+
${cleanFunctionForEmbedding(parseData)}
|
|
85
|
+
${cleanFunctionForEmbedding(trackEvents)}
|
|
86
|
+
parseData(${dataVariableName},{site:"${config.site}",tag:"${config.tag}"},trackEvents,${config.track_web_events},'{{platform}}');
|
|
87
|
+
//replace handlebars
|
|
88
|
+
|
|
89
|
+
parseData(${dataVariableName},{site:"${config.site}",tag:"${config.tag}"},trackEvents,${config.track_web_events},'{{platform}}');
|
|
90
|
+
${config.track_web_events
|
|
91
|
+
? `trackEvents("${config.tag}",'{{platform}}',null,'{{{macros}}}');`
|
|
92
|
+
: ``
|
|
93
|
+
}
|
|
94
|
+
window.lytxApi.event = trackEvents;
|
|
95
|
+
window.lytxApi.capture = function(eventName, customData) {
|
|
96
|
+
window.lytxApi.event("${config.tag}", "{{platform}}", { custom: eventName }, "", customData || undefined);
|
|
97
|
+
};
|
|
98
|
+
})();
|
|
99
|
+
`;
|
|
100
|
+
|
|
101
|
+
return jsTemplate;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
function buildQueryString(queryParams: QueryParams): string {
|
|
108
|
+
// Filter out unwanted keys
|
|
109
|
+
const filteredParams = Object.entries(queryParams).filter(([key]) => key !== 'account' && key !== 'platform');
|
|
110
|
+
|
|
111
|
+
// Convert the object to a query string
|
|
112
|
+
const queryString = filteredParams.map(([key, value]) => {
|
|
113
|
+
return encodeURIComponent(key) + '=' + encodeURIComponent(value.join('&'));
|
|
114
|
+
}).join('&');
|
|
115
|
+
|
|
116
|
+
return queryString ? `&${queryString}` : '';
|
|
117
|
+
}
|