@mherod/get-cookie 4.3.2 → 4.4.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.
Files changed (41) hide show
  1. package/.claude/settings.local.json +3 -0
  2. package/.dependency-cruiser.js +277 -0
  3. package/.husky/commit-msg +0 -0
  4. package/.husky/pre-commit +0 -0
  5. package/.husky/pre-push +0 -0
  6. package/README.md +106 -48
  7. package/biome.json +39 -16
  8. package/dist/cli.cjs +76 -3
  9. package/dist/cli.cjs.map +1 -1
  10. package/dist/index.cjs +76 -2
  11. package/dist/index.cjs.map +1 -1
  12. package/dist/index.d.cts +647 -126
  13. package/dist/index.d.ts +647 -126
  14. package/dist/index.js +76 -2
  15. package/dist/index.js.map +1 -1
  16. package/dist/tsconfig.tsbuildinfo +1 -1
  17. package/eslint.config.js +23 -2
  18. package/examples/auth-tokens.ts +143 -0
  19. package/examples/chrome-cookies-demo.sh +117 -0
  20. package/examples/chrome-profile-demo.sh +126 -0
  21. package/examples/cli-examples.sh +0 -0
  22. package/examples/comprehensive-demo.ts +202 -0
  23. package/examples/curl-demo.sh +102 -0
  24. package/examples/curl-integration.sh +276 -0
  25. package/examples/curl-with-url.sh +136 -0
  26. package/examples/deduplication-demo.sh +110 -0
  27. package/examples/final-chrome-demo.sh +115 -0
  28. package/examples/github-api.sh +101 -0
  29. package/examples/github-private-access.sh +118 -0
  30. package/examples/list-profiles-demo.sh +120 -0
  31. package/examples/proper-curl-usage.sh +120 -0
  32. package/examples/simple-curl.sh +95 -0
  33. package/examples/test-expired-filtering.sh +68 -0
  34. package/examples/test-github-access.sh +245 -0
  35. package/examples/test-github-auth-improved.sh +136 -0
  36. package/examples/working-curl.sh +117 -0
  37. package/examples/working-github-auth.sh +87 -0
  38. package/package.json +46 -27
  39. package/tsconfig.cli.json +5 -1
  40. package/tsup.cli.ts +31 -1
  41. package/tsup.lib.ts +11 -1
package/eslint.config.js CHANGED
@@ -64,13 +64,34 @@ export default [
64
64
  },
65
65
  ],
66
66
  "@typescript-eslint/no-floating-promises": "error",
67
- "@typescript-eslint/no-misused-promises": "error",
67
+ "@typescript-eslint/no-misused-promises": [
68
+ "error",
69
+ {
70
+ checksVoidReturn: {
71
+ arguments: false,
72
+ attributes: false,
73
+ properties: false,
74
+ returns: true,
75
+ variables: true,
76
+ },
77
+ checksConditionals: true,
78
+ },
79
+ ],
68
80
  "@typescript-eslint/await-thenable": "error",
69
- "@typescript-eslint/no-unnecessary-type-assertion": "error",
81
+ "@typescript-eslint/require-await": "error",
82
+ "@typescript-eslint/promise-function-async": "error",
83
+ "@typescript-eslint/prefer-promise-reject-errors": "error",
70
84
  "@typescript-eslint/prefer-nullish-coalescing": "error",
71
85
  "@typescript-eslint/prefer-optional-chain": "error",
72
86
  "@typescript-eslint/strict-boolean-expressions": "error",
73
87
  "@typescript-eslint/no-unnecessary-condition": "error",
88
+ "@typescript-eslint/no-unsafe-assignment": "error",
89
+ "@typescript-eslint/no-unsafe-return": "error",
90
+ "@typescript-eslint/no-unsafe-member-access": "error",
91
+ "@typescript-eslint/no-unsafe-call": "error",
92
+ "@typescript-eslint/no-unsafe-argument": "error",
93
+ "@typescript-eslint/no-unsafe-enum-comparison": "error",
94
+ "@typescript-eslint/prefer-readonly": "error",
74
95
  "import/order": [
75
96
  "error",
76
97
  {
@@ -0,0 +1,143 @@
1
+ #!/usr/bin/env tsx
2
+ /**
3
+ * Example: Extracting authentication tokens from browser cookies
4
+ * This demonstrates how to use get-cookie for extracting auth tokens
5
+ * for API automation or testing purposes
6
+ */
7
+
8
+ import { getCookie } from "../src";
9
+
10
+ interface AuthToken {
11
+ site: string;
12
+ tokenName: string;
13
+ value: string;
14
+ browser: string;
15
+ expiry: Date | string | number | null;
16
+ }
17
+
18
+ async function extractAuthTokens() {
19
+ console.log("šŸ” Authentication Token Extraction Example\n");
20
+ console.log("=".repeat(50));
21
+
22
+ // Common authentication cookie patterns
23
+ const authPatterns = [
24
+ {
25
+ site: "github.com",
26
+ cookies: ["user_session", "_gh_sess", "dotcom_user"],
27
+ },
28
+ {
29
+ site: "google.com",
30
+ cookies: ["OSID", "SID", "HSID", "SSID", "APISID", "SAPISID"],
31
+ },
32
+ { site: "twitter.com", cookies: ["auth_token", "ct0", "kdt"] },
33
+ { site: "linkedin.com", cookies: ["li_at", "JSESSIONID"] },
34
+ { site: "stackoverflow.com", cookies: ["acct", "prov"] },
35
+ ];
36
+
37
+ const foundTokens: AuthToken[] = [];
38
+
39
+ for (const pattern of authPatterns) {
40
+ console.log(`\nšŸ” Checking ${pattern.site}...`);
41
+
42
+ for (const cookieName of pattern.cookies) {
43
+ try {
44
+ const cookies = await getCookie({
45
+ name: cookieName,
46
+ domain: pattern.site,
47
+ });
48
+
49
+ if (cookies.length > 0) {
50
+ cookies.forEach((cookie) => {
51
+ foundTokens.push({
52
+ site: pattern.site,
53
+ tokenName: cookieName,
54
+ value: `${cookie.value.substring(0, 20)}...`, // Truncate for security
55
+ browser: cookie.meta?.browser || "Unknown",
56
+ expiry: cookie.expiry || null,
57
+ });
58
+
59
+ console.log(
60
+ ` āœ“ Found ${cookieName} in ${cookie.meta?.browser || "Unknown"}`,
61
+ );
62
+ });
63
+ }
64
+ } catch (_error) {
65
+ // Cookie not found or error accessing
66
+ }
67
+ }
68
+ }
69
+
70
+ // Summary
71
+ console.log(`\n${"=".repeat(50)}`);
72
+ console.log("šŸ“Š Summary of Found Authentication Tokens\n");
73
+
74
+ if (foundTokens.length === 0) {
75
+ console.log(
76
+ "No authentication tokens found. Make sure you're logged into these sites.",
77
+ );
78
+ } else {
79
+ // Group by site
80
+ const bySite = foundTokens.reduce(
81
+ (acc, token) => {
82
+ if (!acc[token.site]) {
83
+ acc[token.site] = [];
84
+ }
85
+ acc[token.site]?.push(token);
86
+ return acc;
87
+ },
88
+ {} as Record<string, AuthToken[]>,
89
+ );
90
+
91
+ Object.entries(bySite).forEach(([site, tokens]) => {
92
+ console.log(`\n${site}:`);
93
+ tokens.forEach((token) => {
94
+ const expiryInfo =
95
+ token.expiry instanceof Date
96
+ ? `expires ${new Date(token.expiry).toLocaleDateString()}`
97
+ : token.expiry === "Infinity"
98
+ ? "session cookie"
99
+ : "unknown expiry";
100
+
101
+ console.log(` • ${token.tokenName} (${token.browser}, ${expiryInfo})`);
102
+ console.log(` Value: ${token.value}`);
103
+ });
104
+ });
105
+
106
+ // Security reminder
107
+ console.log("\nāš ļø Security Reminder:");
108
+ console.log("These are sensitive authentication tokens. Never:");
109
+ console.log(" - Share them publicly");
110
+ console.log(" - Commit them to version control");
111
+ console.log(" - Use them outside of their intended purpose");
112
+ }
113
+
114
+ // Example: Using tokens for API requests
115
+ console.log(`\n${"=".repeat(50)}`);
116
+ console.log("šŸ’” Example: Using GitHub token for API request\n");
117
+
118
+ const githubSession = foundTokens.find(
119
+ (t) => t.site === "github.com" && t.tokenName === "user_session",
120
+ );
121
+
122
+ if (githubSession) {
123
+ console.log("To use this token with GitHub API:");
124
+ console.log("```javascript");
125
+ console.log(
126
+ "const response = await fetch('https://api.github.com/user', {",
127
+ );
128
+ console.log(" headers: {");
129
+ console.log(" 'Cookie': `user_session=\\$\\{token\\}`,");
130
+ console.log(" 'User-Agent': 'Your-App-Name'");
131
+ console.log(" }");
132
+ console.log("});");
133
+ console.log("```");
134
+ console.log("\nNote: Most modern APIs prefer OAuth tokens over cookies.");
135
+ } else {
136
+ console.log(
137
+ "No GitHub session found. Log into GitHub in your browser first.",
138
+ );
139
+ }
140
+ }
141
+
142
+ // Run the example
143
+ extractAuthTokens().catch(console.error);
@@ -0,0 +1,117 @@
1
+ #!/bin/bash
2
+
3
+ # Chrome-specific cookie extraction demo
4
+ echo "šŸŖ Chrome Cookie Extraction with get-cookie"
5
+ echo "==========================================="
6
+ echo ""
7
+
8
+ # Basic Chrome cookie extraction
9
+ echo "1ļøāƒ£ Basic Chrome cookie extraction:"
10
+ echo "─────────────────────────────────"
11
+ echo "Command: get-cookie --url https://github.com --browser chrome --render"
12
+ echo ""
13
+ COOKIES=$(get-cookie --url https://github.com --browser chrome --render 2>/dev/null | head -c 100)
14
+ echo "Output (truncated): $COOKIES..."
15
+ echo ""
16
+
17
+ # JSON output for debugging
18
+ echo "2ļøāƒ£ Chrome cookies in JSON format:"
19
+ echo "────────────────────────────────"
20
+ echo "Command: get-cookie --url https://github.com --browser chrome --output json"
21
+ echo ""
22
+ get-cookie --url https://github.com --browser chrome --output json 2>/dev/null | jq '.[:2]'
23
+ echo ""
24
+
25
+ # Filtering duplicates
26
+ echo "3ļøāƒ£ Handling duplicate cookies:"
27
+ echo "─────────────────────────────"
28
+ echo "Chrome may have duplicate cookies from different profiles."
29
+ echo ""
30
+ echo "Session cookies found:"
31
+ get-cookie --url https://github.com --browser chrome --output json 2>/dev/null | \
32
+ jq -r '.[] | select(.name == "user_session") | " • \(.value[0:20])... (\(.value | length) chars)"'
33
+ echo ""
34
+
35
+ # Smart filtering
36
+ echo "4ļøāƒ£ Smart cookie filtering (recommended):"
37
+ echo "───────────────────────────────────────"
38
+ echo "Filter to get the longest (most likely valid) cookie value:"
39
+ echo ""
40
+ cat << 'EOF'
41
+ VALID_SESSION=$(get-cookie --url https://github.com --browser chrome --output json | \
42
+ jq -r '.[] | select(.name == "user_session" and (.value | length) > 20) | .value' | \
43
+ head -1)
44
+ EOF
45
+ echo ""
46
+
47
+ # Using with curl
48
+ echo "5ļøāƒ£ Using Chrome cookies with curl:"
49
+ echo "────────────────────────────────"
50
+ echo "Simple approach (may fail with duplicates):"
51
+ echo 'curl -H "Cookie: $(get-cookie --url <URL> --browser chrome --render)" <URL>'
52
+ echo ""
53
+ echo "Robust approach (with filtering):"
54
+ cat << 'EOF'
55
+ # Get deduplicated cookies (longest value wins)
56
+ COOKIES=$(get-cookie --url <URL> --browser chrome --output json | \
57
+ jq -r 'group_by(.name) | map(max_by(.value | length)) |
58
+ .[] | "\(.name)=\(.value)"' | tr '\n' ';')
59
+
60
+ curl -H "Cookie: $COOKIES" <URL>
61
+ EOF
62
+ echo ""
63
+
64
+ # Testing authentication
65
+ echo "6ļøāƒ£ Testing GitHub authentication with Chrome cookies:"
66
+ echo "───────────────────────────────────────────────────"
67
+ COOKIES=$(get-cookie --url https://github.com --browser chrome --output json 2>/dev/null | \
68
+ jq -r 'group_by(.name) | map(max_by(.value | length)) | .[] | "\(.name)=\(.value)"' | tr '\n' ';')
69
+
70
+ echo -n "Testing with deduplicated cookies: "
71
+ HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" \
72
+ -H "Cookie: $COOKIES" \
73
+ -H "User-Agent: Mozilla/5.0" \
74
+ "https://github.com/settings/profile")
75
+
76
+ if [ "$HTTP_CODE" = "200" ]; then
77
+ echo "āœ… Success (HTTP 200)"
78
+ elif [ "$HTTP_CODE" = "302" ]; then
79
+ echo "āŒ Redirected to login (HTTP 302)"
80
+ else
81
+ echo "āš ļø HTTP $HTTP_CODE"
82
+ fi
83
+ echo ""
84
+
85
+ # Check cookie counts
86
+ echo "7ļøāƒ£ Cookie statistics:"
87
+ echo "──────────────────"
88
+ TOTAL=$(get-cookie --url https://github.com --browser chrome --output json 2>/dev/null | jq 'length')
89
+ UNIQUE=$(get-cookie --url https://github.com --browser chrome --output json 2>/dev/null | jq '[.[] | .name] | unique | length')
90
+ echo "• Total cookies: $TOTAL"
91
+ echo "• Unique cookie names: $UNIQUE"
92
+ echo "• Duplicates: $((TOTAL - UNIQUE))"
93
+ echo ""
94
+
95
+ # Expired cookie filtering
96
+ echo "8ļøāƒ£ Expired cookie filtering:"
97
+ echo "──────────────────────────"
98
+ WITHOUT=$(get-cookie --url https://github.com --browser chrome --output json 2>/dev/null | jq 'length')
99
+ WITH=$(get-cookie --url https://github.com --browser chrome --output json --include-expired 2>/dev/null | jq 'length')
100
+ echo "• Without --include-expired: $WITHOUT cookies"
101
+ echo "• With --include-expired: $WITH cookies"
102
+ if [ "$WITH" -gt "$WITHOUT" ]; then
103
+ echo "• āœ… Filtered out $((WITH - WITHOUT)) expired cookies"
104
+ else
105
+ echo "• ā„¹ļø No expired cookies found"
106
+ fi
107
+ echo ""
108
+
109
+ echo "šŸ’” Key Insights:"
110
+ echo "──────────────"
111
+ echo "• Chrome may store duplicate cookies from different profiles"
112
+ echo "• The --render flag outputs all cookies, including duplicates"
113
+ echo "• For authentication, deduplicate by taking the longest value"
114
+ echo "• Expired cookies are filtered by default (use --include-expired to see all)"
115
+ echo "• Use JSON output + jq for precise cookie control"
116
+ echo ""
117
+ echo "āœ… Chrome cookie extraction complete!"
@@ -0,0 +1,126 @@
1
+ #!/bin/bash
2
+
3
+ # Chrome Profile Selection Demo
4
+ echo "šŸŖ Chrome Profile Selection with get-cookie"
5
+ echo "==========================================="
6
+ echo ""
7
+ echo "The new --profile option allows targeting specific Chrome profiles by name."
8
+ echo ""
9
+
10
+ # List available Chrome profiles
11
+ echo "šŸ“‹ Available Chrome Profiles:"
12
+ echo "──────────────────────────"
13
+ if [ -f ~/Library/Application\ Support/Google/Chrome/Local\ State ]; then
14
+ cat ~/Library/Application\ Support/Google/Chrome/Local\ State | \
15
+ jq -r '.profile.info_cache | to_entries | .[] | " • \(.value.name) (directory: \(.key))"'
16
+ else
17
+ echo " Chrome Local State file not found"
18
+ fi
19
+ echo ""
20
+
21
+ # Demonstrate profile-specific extraction
22
+ echo "šŸŽÆ Profile-Specific Cookie Extraction:"
23
+ echo "────────────────────────────────────"
24
+ echo ""
25
+
26
+ echo "1ļøāƒ£ Extract from a specific profile by name:"
27
+ echo " Command: get-cookie --url https://github.com --browser chrome --profile \"plugg.in\" --render"
28
+ echo ""
29
+ COOKIES=$(get-cookie --url https://github.com --browser chrome --profile "plugg.in" --render 2>/dev/null | head -c 80)
30
+ echo " Output: $COOKIES..."
31
+ echo ""
32
+
33
+ echo "2ļøāƒ£ Compare different profiles for the same cookie:"
34
+ echo ""
35
+ echo " Default/Personal profile:"
36
+ echo " $ get-cookie user_session github.com --browser chrome --profile \"Personal\" --render"
37
+ PERSONAL=$(get-cookie user_session github.com --browser chrome --profile "Personal" --render 2>/dev/null)
38
+ if [ -n "$PERSONAL" ]; then
39
+ VALUE=$(echo "$PERSONAL" | cut -d'=' -f2)
40
+ echo " Result: user_session=${VALUE:0:20}... (${#VALUE} chars)"
41
+ else
42
+ echo " Result: No user_session cookie found"
43
+ fi
44
+ echo ""
45
+
46
+ echo " Profile 9/plugg.in profile:"
47
+ echo " $ get-cookie user_session github.com --browser chrome --profile \"plugg.in\" --render"
48
+ PLUGIN=$(get-cookie user_session github.com --browser chrome --profile "plugg.in" --render 2>/dev/null)
49
+ if [ -n "$PLUGIN" ]; then
50
+ VALUE=$(echo "$PLUGIN" | cut -d'=' -f2)
51
+ echo " Result: user_session=${VALUE:0:20}... (${#VALUE} chars)"
52
+ else
53
+ echo " Result: No user_session cookie found"
54
+ fi
55
+ echo ""
56
+
57
+ # Show the benefit
58
+ echo "šŸ’” Benefits of Profile Selection:"
59
+ echo "───────────────────────────────"
60
+ echo "• Avoid cookie conflicts between profiles"
61
+ echo "• Target the correct logged-in session"
62
+ echo "• No need for deduplication when using specific profile"
63
+ echo "• Faster queries (only searches one profile)"
64
+ echo ""
65
+
66
+ # Practical curl example
67
+ echo "šŸ”§ Practical Example with curl:"
68
+ echo "─────────────────────────────"
69
+ echo ""
70
+ echo "Use the correct profile for authenticated requests:"
71
+ echo ""
72
+ cat << 'EOF'
73
+ # Get cookies from your work profile
74
+ COOKIES=$(get-cookie --url https://github.com --browser chrome --profile "Work" --render)
75
+ curl -H "Cookie: $COOKIES" https://github.com/settings/profile
76
+
77
+ # Get cookies from your personal profile
78
+ COOKIES=$(get-cookie --url https://github.com --browser chrome --profile "Personal" --render)
79
+ curl -H "Cookie: $COOKIES" https://github.com/settings/profile
80
+ EOF
81
+ echo ""
82
+
83
+ # Test with curl
84
+ echo "🧪 Live Test with GitHub:"
85
+ echo "──────────────────────"
86
+ echo ""
87
+
88
+ test_profile() {
89
+ local profile=$1
90
+ echo -n "Testing profile '$profile': "
91
+
92
+ COOKIES=$(get-cookie --url https://github.com/settings/profile --browser chrome --profile "$profile" --render 2>/dev/null)
93
+
94
+ if [ -z "$COOKIES" ]; then
95
+ echo "āŒ No cookies found"
96
+ return
97
+ fi
98
+
99
+ HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" \
100
+ -H "Cookie: $COOKIES" \
101
+ -H "User-Agent: Mozilla/5.0" \
102
+ "https://github.com/settings/profile")
103
+
104
+ if [ "$HTTP_CODE" = "200" ]; then
105
+ echo "āœ… Authenticated (HTTP 200)"
106
+ elif [ "$HTTP_CODE" = "302" ]; then
107
+ echo "šŸ”„ Redirected to login (HTTP 302)"
108
+ else
109
+ echo "āš ļø HTTP $HTTP_CODE"
110
+ fi
111
+ }
112
+
113
+ # Test each profile that might have GitHub cookies
114
+ test_profile "Personal"
115
+ test_profile "plugg.in"
116
+ echo ""
117
+
118
+ echo "šŸ“ Usage Notes:"
119
+ echo "────────────"
120
+ echo "• Profile names are case-insensitive"
121
+ echo "• You can use either the display name (e.g., \"Personal\") or directory name (e.g., \"Default\")"
122
+ echo "• If no --profile is specified, all profiles are queried"
123
+ echo "• Combine with --include-all to see cookies from all profiles even when one is selected"
124
+ echo ""
125
+
126
+ echo "āœ… Profile selection feature is working perfectly!"
File without changes
@@ -0,0 +1,202 @@
1
+ #!/usr/bin/env tsx
2
+ /**
3
+ * Comprehensive demonstration of get-cookie library features
4
+ * This example shows various ways to query and work with browser cookies
5
+ */
6
+
7
+ import { getCookie } from "../src";
8
+ import { CookieStrategyFactory } from "../src/cli/services/CookieStrategyFactory";
9
+
10
+ async function demonstrateFeatures() {
11
+ console.log("šŸŖ Get-Cookie Library Demonstration\n");
12
+ console.log("=".repeat(50));
13
+
14
+ // 1. Basic cookie retrieval
15
+ console.log("\nšŸ“Œ Example 1: Get specific cookies by name");
16
+ console.log("-".repeat(40));
17
+ try {
18
+ const githubSession = await getCookie({
19
+ name: "user_session",
20
+ domain: "github.com",
21
+ });
22
+
23
+ if (githubSession.length > 0) {
24
+ console.log(
25
+ `Found ${githubSession.length} GitHub user_session cookie(s):`,
26
+ );
27
+ githubSession.forEach((cookie, i) => {
28
+ console.log(
29
+ ` ${i + 1}. Browser: ${cookie.meta?.browser || "Unknown"}`,
30
+ );
31
+ console.log(
32
+ ` Profile: ${cookie.meta?.file?.split("/").slice(-2, -1)[0] || "Default"}`,
33
+ );
34
+ console.log(` Expires: ${cookie.expiry}`);
35
+ console.log(` Decrypted: ${cookie.meta?.decrypted || "N/A"}`);
36
+ });
37
+ } else {
38
+ console.log("No GitHub user_session cookies found");
39
+ }
40
+ } catch (error) {
41
+ console.error("Error retrieving cookies:", error);
42
+ }
43
+
44
+ // 2. Wildcard search
45
+ console.log("\nšŸ“Œ Example 2: Wildcard search for all cookies");
46
+ console.log("-".repeat(40));
47
+ try {
48
+ const allGoogleCookies = await getCookie({
49
+ name: "%", // Wildcard for any name
50
+ domain: "google.com",
51
+ });
52
+
53
+ if (allGoogleCookies.length > 0) {
54
+ // Group by cookie name
55
+ const cookieNames = [...new Set(allGoogleCookies.map((c) => c.name))];
56
+ console.log(`Found ${allGoogleCookies.length} Google cookies:`);
57
+ console.log(`Unique cookie names (${cookieNames.length}):`);
58
+ cookieNames.slice(0, 10).forEach((name) => {
59
+ const count = allGoogleCookies.filter((c) => c.name === name).length;
60
+ console.log(` - ${name} (${count} instance${count > 1 ? "s" : ""})`);
61
+ });
62
+ if (cookieNames.length > 10) {
63
+ console.log(` ... and ${cookieNames.length - 10} more`);
64
+ }
65
+ } else {
66
+ console.log("No Google cookies found");
67
+ }
68
+ } catch (error) {
69
+ console.error("Error retrieving cookies:", error);
70
+ }
71
+
72
+ // 3. Browser-specific queries
73
+ console.log("\nšŸ“Œ Example 3: Browser-specific strategies");
74
+ console.log("-".repeat(40));
75
+
76
+ const browsers = ["chrome", "firefox", "safari"];
77
+ for (const browser of browsers) {
78
+ try {
79
+ const strategy = CookieStrategyFactory.createStrategy(browser);
80
+ const cookies = await strategy.queryCookies("%", "github.com");
81
+
82
+ if (cookies.length > 0) {
83
+ console.log(
84
+ `āœ“ ${browser.toUpperCase()}: Found ${cookies.length} GitHub cookies`,
85
+ );
86
+ } else {
87
+ console.log(
88
+ `āœ— ${browser.toUpperCase()}: No GitHub cookies or browser not available`,
89
+ );
90
+ }
91
+ } catch (_error) {
92
+ console.log(`āœ— ${browser.toUpperCase()}: Not available on this system`);
93
+ }
94
+ }
95
+
96
+ // 4. Composite strategy (all browsers)
97
+ console.log("\nšŸ“Œ Example 4: Composite strategy (query all browsers)");
98
+ console.log("-".repeat(40));
99
+ try {
100
+ const compositeStrategy = CookieStrategyFactory.createStrategy();
101
+ const allCookies = await compositeStrategy.queryCookies("%", "github.com");
102
+
103
+ // Group by browser
104
+ const browserGroups = allCookies.reduce(
105
+ (acc, cookie) => {
106
+ const browser = cookie.meta?.browser || "Unknown";
107
+ if (!acc[browser]) {
108
+ acc[browser] = [];
109
+ }
110
+ acc[browser].push(cookie);
111
+ return acc;
112
+ },
113
+ {} as Record<string, typeof allCookies>,
114
+ );
115
+
116
+ console.log("Cookies found across all browsers:");
117
+ Object.entries(browserGroups).forEach(([browser, cookies]) => {
118
+ const uniqueNames = [...new Set(cookies.map((c) => c.name))];
119
+ console.log(
120
+ ` ${browser}: ${cookies.length} cookies (${uniqueNames.length} unique names)`,
121
+ );
122
+ });
123
+ } catch (error) {
124
+ console.error("Error with composite strategy:", error);
125
+ }
126
+
127
+ // 5. Session vs Persistent cookies
128
+ console.log("\nšŸ“Œ Example 5: Session vs Persistent cookies");
129
+ console.log("-".repeat(40));
130
+ try {
131
+ const allCookies = await getCookie({
132
+ name: "%",
133
+ domain: "google.com",
134
+ });
135
+
136
+ const sessionCookies = allCookies.filter(
137
+ (c) =>
138
+ c.expiry === "Infinity" || c.expiry === undefined || c.expiry === null,
139
+ );
140
+ const persistentCookies = allCookies.filter(
141
+ (c) => c.expiry && c.expiry !== "Infinity",
142
+ );
143
+
144
+ console.log(`Session cookies: ${sessionCookies.length}`);
145
+ console.log(`Persistent cookies: ${persistentCookies.length}`);
146
+
147
+ if (persistentCookies.length > 0) {
148
+ // Find the cookie expiring soonest
149
+ const cookiesWithDates = persistentCookies.filter(
150
+ (c): c is typeof c & { expiry: Date } => c.expiry instanceof Date,
151
+ );
152
+ const soonest = cookiesWithDates.sort((a, b) => {
153
+ const dateA = a.expiry.getTime();
154
+ const dateB = b.expiry.getTime();
155
+ return dateA - dateB;
156
+ })[0];
157
+
158
+ if (soonest) {
159
+ const daysUntilExpiry = Math.ceil(
160
+ (soonest.expiry.getTime() - Date.now()) / (1000 * 60 * 60 * 24),
161
+ );
162
+ console.log(
163
+ `Cookie expiring soonest: ${soonest.name} (${daysUntilExpiry} days)`,
164
+ );
165
+ }
166
+ }
167
+ } catch (error) {
168
+ console.error("Error analyzing cookies:", error);
169
+ }
170
+
171
+ // 6. Performance measurement
172
+ console.log("\nšŸ“Œ Example 6: Performance measurement");
173
+ console.log("-".repeat(40));
174
+
175
+ const iterations = 5;
176
+ const times: number[] = [];
177
+
178
+ for (let i = 0; i < iterations; i++) {
179
+ const start = Date.now();
180
+ await getCookie({
181
+ name: "%",
182
+ domain: "github.com",
183
+ });
184
+ const elapsed = Date.now() - start;
185
+ times.push(elapsed);
186
+ }
187
+
188
+ const avgTime = times.reduce((a, b) => a + b, 0) / times.length;
189
+ const minTime = Math.min(...times);
190
+ const maxTime = Math.max(...times);
191
+
192
+ console.log(`Query performance (${iterations} iterations):`);
193
+ console.log(` Average: ${avgTime.toFixed(2)}ms`);
194
+ console.log(` Min: ${minTime}ms`);
195
+ console.log(` Max: ${maxTime}ms`);
196
+
197
+ console.log(`\n${"=".repeat(50)}`);
198
+ console.log("āœ… Demonstration complete!");
199
+ }
200
+
201
+ // Run the demonstration
202
+ demonstrateFeatures().catch(console.error);