pdauth 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/PROXY-SPEC.md +159 -0
- package/README.md +142 -0
- package/bin/ga.mjs +329 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +88 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/apps.d.ts +8 -0
- package/dist/commands/apps.d.ts.map +1 -0
- package/dist/commands/apps.js +76 -0
- package/dist/commands/apps.js.map +1 -0
- package/dist/commands/config.d.ts +5 -0
- package/dist/commands/config.d.ts.map +1 -0
- package/dist/commands/config.js +58 -0
- package/dist/commands/config.js.map +1 -0
- package/dist/commands/connect.d.ts +6 -0
- package/dist/commands/connect.d.ts.map +1 -0
- package/dist/commands/connect.js +67 -0
- package/dist/commands/connect.js.map +1 -0
- package/dist/commands/index.d.ts +7 -0
- package/dist/commands/index.d.ts.map +1 -0
- package/dist/commands/index.js +7 -0
- package/dist/commands/index.js.map +1 -0
- package/dist/commands/proxy.d.ts +12 -0
- package/dist/commands/proxy.d.ts.map +1 -0
- package/dist/commands/proxy.js +127 -0
- package/dist/commands/proxy.js.map +1 -0
- package/dist/commands/status.d.ts +10 -0
- package/dist/commands/status.d.ts.map +1 -0
- package/dist/commands/status.js +117 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/tools.d.ts +10 -0
- package/dist/commands/tools.d.ts.map +1 -0
- package/dist/commands/tools.js +123 -0
- package/dist/commands/tools.js.map +1 -0
- package/dist/config.d.ts +21 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +59 -0
- package/dist/config.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/pipedream.d.ts +52 -0
- package/dist/pipedream.d.ts.map +1 -0
- package/dist/pipedream.js +142 -0
- package/dist/pipedream.js.map +1 -0
- package/package.json +46 -0
- package/src/cli.ts +111 -0
- package/src/commands/apps.ts +88 -0
- package/src/commands/config.ts +68 -0
- package/src/commands/connect.ts +76 -0
- package/src/commands/index.ts +6 -0
- package/src/commands/proxy.ts +155 -0
- package/src/commands/status.ts +143 -0
- package/src/commands/tools.ts +150 -0
- package/src/config.ts +78 -0
- package/src/index.ts +6 -0
- package/src/pipedream.ts +216 -0
- package/tsconfig.json +20 -0
package/PROXY-SPEC.md
ADDED
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
# pdauth proxy Command Specification
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
Add a `proxy` command to pdauth that allows making authenticated HTTP requests to any Pipedream-connected API using the SDK's built-in proxy feature.
|
|
6
|
+
|
|
7
|
+
## SDK Already Has Proxy
|
|
8
|
+
|
|
9
|
+
The `@pipedream/sdk` has a `client.proxy` object with these methods:
|
|
10
|
+
- `client.proxy.get(request)`
|
|
11
|
+
- `client.proxy.post(request)`
|
|
12
|
+
- `client.proxy.put(request)`
|
|
13
|
+
- `client.proxy.delete(request)`
|
|
14
|
+
- `client.proxy.patch(request)`
|
|
15
|
+
|
|
16
|
+
Each takes:
|
|
17
|
+
```typescript
|
|
18
|
+
{
|
|
19
|
+
url: string; // Target API URL (relative for dynamic domain apps)
|
|
20
|
+
externalUserId: string; // User ID
|
|
21
|
+
accountId: string; // Account ID (e.g., "apn_1234567")
|
|
22
|
+
params?: Record<string, string>; // Query params
|
|
23
|
+
headers?: Record<string, string>; // Custom headers
|
|
24
|
+
body?: Record<string, unknown>; // Request body (POST/PUT/PATCH)
|
|
25
|
+
}
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Command Interface
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
pdauth proxy <app> <path> [options]
|
|
32
|
+
|
|
33
|
+
Arguments:
|
|
34
|
+
app - App slug (e.g., zoho_mail, slack, notion)
|
|
35
|
+
path - API path (e.g., /api/accounts, /api/accounts/123/folders)
|
|
36
|
+
|
|
37
|
+
Options:
|
|
38
|
+
-X, --method <method> HTTP method (GET|POST|PUT|DELETE|PATCH) [default: GET]
|
|
39
|
+
-u, --user <userId> External user ID [default: from config]
|
|
40
|
+
-d, --data <json> Request body as JSON string
|
|
41
|
+
-H, --header <header> Custom header (can be repeated: -H "X-Foo: bar" -H "X-Baz: qux")
|
|
42
|
+
-q, --query <param> Query parameter (can be repeated: -q "limit=10" -q "offset=0")
|
|
43
|
+
-j, --json Output as JSON (default: pretty print)
|
|
44
|
+
-v, --verbose Show request details
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Examples
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
# GET request
|
|
51
|
+
pdauth proxy zoho_mail /api/accounts --user telegram:5439689035
|
|
52
|
+
|
|
53
|
+
# GET with query params
|
|
54
|
+
pdauth proxy zoho_mail /api/accounts/123/folders -q "limit=50" --user telegram:5439689035
|
|
55
|
+
|
|
56
|
+
# POST with JSON body
|
|
57
|
+
pdauth proxy zoho_mail /api/accounts/123/folders \
|
|
58
|
+
-X POST \
|
|
59
|
+
-d '{"folderName": "Projects"}' \
|
|
60
|
+
--user telegram:5439689035
|
|
61
|
+
|
|
62
|
+
# PUT with headers
|
|
63
|
+
pdauth proxy slack /api/chat.postMessage \
|
|
64
|
+
-X POST \
|
|
65
|
+
-d '{"channel": "C123", "text": "Hello"}' \
|
|
66
|
+
-H "Content-Type: application/json" \
|
|
67
|
+
--user telegram:5439689035
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Implementation Steps
|
|
71
|
+
|
|
72
|
+
1. Create `src/commands/proxy.ts`:
|
|
73
|
+
- Import getClient from pipedream.ts
|
|
74
|
+
- Import listAccounts to find account ID for app + user
|
|
75
|
+
- Parse CLI arguments
|
|
76
|
+
- Call appropriate proxy method (get/post/put/delete/patch)
|
|
77
|
+
- Output response
|
|
78
|
+
|
|
79
|
+
2. Add to `src/commands/index.ts`:
|
|
80
|
+
- Export registerProxyCommand
|
|
81
|
+
|
|
82
|
+
3. Add to `src/cli.ts`:
|
|
83
|
+
- Register the proxy command
|
|
84
|
+
|
|
85
|
+
## Code Structure
|
|
86
|
+
|
|
87
|
+
```typescript
|
|
88
|
+
// src/commands/proxy.ts
|
|
89
|
+
import { Command } from 'commander';
|
|
90
|
+
import { getClient, listAccounts } from '../pipedream.js';
|
|
91
|
+
|
|
92
|
+
export function registerProxyCommand(program: Command): void {
|
|
93
|
+
program
|
|
94
|
+
.command('proxy <app> <path>')
|
|
95
|
+
.description('Make authenticated API request via Pipedream proxy')
|
|
96
|
+
.option('-X, --method <method>', 'HTTP method', 'GET')
|
|
97
|
+
.option('-u, --user <userId>', 'External user ID')
|
|
98
|
+
.option('-d, --data <json>', 'Request body JSON')
|
|
99
|
+
.option('-H, --header <header>', 'Custom header', collect, [])
|
|
100
|
+
.option('-q, --query <param>', 'Query parameter', collect, [])
|
|
101
|
+
.option('-j, --json', 'JSON output')
|
|
102
|
+
.option('-v, --verbose', 'Verbose output')
|
|
103
|
+
.action(async (app, path, options) => {
|
|
104
|
+
// 1. Get account ID for app + user
|
|
105
|
+
const accounts = await listAccounts(options.user);
|
|
106
|
+
const account = accounts.find(a => a.app.nameSlug === app);
|
|
107
|
+
if (!account) throw new Error(`No ${app} account connected for user`);
|
|
108
|
+
|
|
109
|
+
// 2. Build request
|
|
110
|
+
const client = getClient();
|
|
111
|
+
const request = {
|
|
112
|
+
url: path, // relative path for dynamic domain apps
|
|
113
|
+
externalUserId: options.user,
|
|
114
|
+
accountId: account.id,
|
|
115
|
+
params: parseParams(options.query),
|
|
116
|
+
headers: parseHeaders(options.header),
|
|
117
|
+
body: options.data ? JSON.parse(options.data) : undefined,
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
// 3. Call proxy
|
|
121
|
+
const method = options.method.toLowerCase();
|
|
122
|
+
const response = await client.proxy[method](request);
|
|
123
|
+
|
|
124
|
+
// 4. Output
|
|
125
|
+
console.log(options.json ? JSON.stringify(response) : response);
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function collect(value: string, previous: string[]) {
|
|
130
|
+
return previous.concat([value]);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function parseParams(params: string[]): Record<string, string> {
|
|
134
|
+
const result: Record<string, string> = {};
|
|
135
|
+
for (const p of params) {
|
|
136
|
+
const [key, ...rest] = p.split('=');
|
|
137
|
+
result[key] = rest.join('=');
|
|
138
|
+
}
|
|
139
|
+
return result;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function parseHeaders(headers: string[]): Record<string, string> {
|
|
143
|
+
const result: Record<string, string> = {};
|
|
144
|
+
for (const h of headers) {
|
|
145
|
+
const [key, ...rest] = h.split(':');
|
|
146
|
+
result[key.trim()] = rest.join(':').trim();
|
|
147
|
+
}
|
|
148
|
+
return result;
|
|
149
|
+
}
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
## Testing
|
|
153
|
+
|
|
154
|
+
```bash
|
|
155
|
+
# After implementation, test with:
|
|
156
|
+
pdauth proxy zoho_mail /api/accounts --user telegram:5439689035 -v
|
|
157
|
+
|
|
158
|
+
# Expected: List of Zoho Mail accounts
|
|
159
|
+
```
|
package/README.md
ADDED
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
# š pdauth
|
|
2
|
+
|
|
3
|
+
**Pipedream OAuth CLI** ā Give AI agents access to 2500+ APIs via dynamic OAuth
|
|
4
|
+
|
|
5
|
+
```
|
|
6
|
+
Agent: "I need Spotify access to manage your playlist"
|
|
7
|
+
ā
|
|
8
|
+
$ pdauth connect spotify
|
|
9
|
+
ā
|
|
10
|
+
š https://pipedream.com/_static/connect.html?token=ctok_xxx&app=spotify
|
|
11
|
+
ā
|
|
12
|
+
User clicks ā OAuth flow ā Done
|
|
13
|
+
ā
|
|
14
|
+
Agent can now call Spotify tools via MCP
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm install -g pdauth
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Quick Start
|
|
24
|
+
|
|
25
|
+
### 1. Configure Pipedream credentials
|
|
26
|
+
|
|
27
|
+
Get your credentials at https://pipedream.com/settings/api
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
pdauth config
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Or set directly:
|
|
34
|
+
```bash
|
|
35
|
+
pdauth config --set clientId=YOUR_CLIENT_ID
|
|
36
|
+
pdauth config --set clientSecret=YOUR_CLIENT_SECRET
|
|
37
|
+
pdauth config --set projectId=YOUR_PROJECT_ID
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### 2. Generate OAuth link for any app
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
# Generate link for Spotify
|
|
44
|
+
pdauth connect spotify
|
|
45
|
+
|
|
46
|
+
# Generate for a specific user
|
|
47
|
+
pdauth connect google_sheets --user pedro@example.com
|
|
48
|
+
|
|
49
|
+
# Copy to clipboard
|
|
50
|
+
pdauth connect slack --copy
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### 3. Check connection status
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
# Show connected accounts
|
|
57
|
+
pdauth status
|
|
58
|
+
|
|
59
|
+
# Show all users
|
|
60
|
+
pdauth status --all
|
|
61
|
+
|
|
62
|
+
# JSON output for scripts
|
|
63
|
+
pdauth status --json
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### 4. Use connected tools
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
# List available tools for an app
|
|
70
|
+
pdauth tools slack
|
|
71
|
+
|
|
72
|
+
# Call a tool
|
|
73
|
+
pdauth call slack.send_message channel=general text="Hello from AI!"
|
|
74
|
+
|
|
75
|
+
# Call with JSON args
|
|
76
|
+
pdauth call notion.create_page --args '{"title": "New Page", "parent_id": "..."}'
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Commands
|
|
80
|
+
|
|
81
|
+
| Command | Description |
|
|
82
|
+
|---------|-------------|
|
|
83
|
+
| `pdauth config` | Configure Pipedream credentials |
|
|
84
|
+
| `pdauth apps [--search <query>]` | List available apps (2500+) |
|
|
85
|
+
| `pdauth app <slug>` | Get info about an app |
|
|
86
|
+
| `pdauth connect <app>` | Generate OAuth link |
|
|
87
|
+
| `pdauth status` | List connected accounts |
|
|
88
|
+
| `pdauth disconnect <app>` | Revoke app access |
|
|
89
|
+
| `pdauth tools <app>` | List MCP tools for an app |
|
|
90
|
+
| `pdauth call <app.tool>` | Invoke an MCP tool |
|
|
91
|
+
|
|
92
|
+
## Options
|
|
93
|
+
|
|
94
|
+
All commands support:
|
|
95
|
+
- `-u, --user <id>` ā Specify user ID (default: "default")
|
|
96
|
+
- `-j, --json` ā Output as JSON
|
|
97
|
+
|
|
98
|
+
## How It Works
|
|
99
|
+
|
|
100
|
+
1. **You run** `pdauth connect <app>` ā generates a secure OAuth link
|
|
101
|
+
2. **User clicks** the link ā Pipedream handles OAuth flow
|
|
102
|
+
3. **Credentials stored** securely in Pipedream (not locally)
|
|
103
|
+
4. **Agent calls tools** via MCP using `pdauth call` or direct MCP
|
|
104
|
+
|
|
105
|
+
Powered by [Pipedream Connect](https://pipedream.com/docs/connect) ā managed OAuth for 2500+ APIs.
|
|
106
|
+
|
|
107
|
+
## For AI Agents (OpenClaw)
|
|
108
|
+
|
|
109
|
+
This CLI is designed for AI agents to request and use OAuth access dynamically:
|
|
110
|
+
|
|
111
|
+
```
|
|
112
|
+
User: "Add this song to my Spotify playlist"
|
|
113
|
+
|
|
114
|
+
Agent: I need Spotify access. Here's a link to authorize:
|
|
115
|
+
https://pipedream.com/_static/connect.html?token=...
|
|
116
|
+
|
|
117
|
+
User: *clicks, authorizes*
|
|
118
|
+
|
|
119
|
+
Agent: *calls pdauth call spotify.add_to_playlist ...*
|
|
120
|
+
ā Added "Song Name" to your playlist!
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
## Environment Variables
|
|
124
|
+
|
|
125
|
+
Instead of `pdauth config`, you can use environment variables:
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
export PIPEDREAM_CLIENT_ID=your_client_id
|
|
129
|
+
export PIPEDREAM_CLIENT_SECRET=your_client_secret
|
|
130
|
+
export PIPEDREAM_PROJECT_ID=your_project_id
|
|
131
|
+
export PIPEDREAM_ENVIRONMENT=development # or production
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
## Links
|
|
135
|
+
|
|
136
|
+
- [Pipedream MCP](https://mcp.pipedream.com) ā Browse all available apps
|
|
137
|
+
- [Pipedream Connect Docs](https://pipedream.com/docs/connect)
|
|
138
|
+
- [OpenClaw](https://openclaw.ai) ā AI agent platform
|
|
139
|
+
|
|
140
|
+
## License
|
|
141
|
+
|
|
142
|
+
MIT Ā© Versatly
|
package/bin/ga.mjs
ADDED
|
@@ -0,0 +1,329 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* ga - Google Analytics CLI powered by pdauth
|
|
5
|
+
*
|
|
6
|
+
* Usage:
|
|
7
|
+
* ga properties List all properties
|
|
8
|
+
* ga report <property> 30-day overview
|
|
9
|
+
* ga traffic <property> Traffic sources breakdown
|
|
10
|
+
* ga devices <property> Device breakdown
|
|
11
|
+
* ga pages <property> Top pages
|
|
12
|
+
* ga compare <property> Compare periods
|
|
13
|
+
* ga franchise All Hale franchises overview
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import { execSync } from 'child_process';
|
|
17
|
+
|
|
18
|
+
const USER = 'telegram:5439689035';
|
|
19
|
+
|
|
20
|
+
function pdauthCall(instruction) {
|
|
21
|
+
const args = JSON.stringify({ instruction });
|
|
22
|
+
const cmd = `pdauth call google_analytics.google_analytics-run-report-in-ga4 --user ${USER} --args '${args}' --json`;
|
|
23
|
+
|
|
24
|
+
try {
|
|
25
|
+
const result = execSync(cmd, { encoding: 'utf-8', timeout: 120000 });
|
|
26
|
+
const parsed = JSON.parse(result);
|
|
27
|
+
return parsed?.content?.[0]?.text || 'No data';
|
|
28
|
+
} catch (e) {
|
|
29
|
+
return `Error: ${e.message}`;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function printHeader(title) {
|
|
34
|
+
console.log('\n' + 'ā'.repeat(60));
|
|
35
|
+
console.log(` š ${title}`);
|
|
36
|
+
console.log('ā'.repeat(60) + '\n');
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
import { writeFileSync, existsSync, readFileSync } from 'fs';
|
|
40
|
+
import { join } from 'path';
|
|
41
|
+
|
|
42
|
+
const ALERTS_FILE = join(process.env.HOME, '.config/pdauth/ga-alerts.json');
|
|
43
|
+
|
|
44
|
+
function loadAlerts() {
|
|
45
|
+
if (existsSync(ALERTS_FILE)) {
|
|
46
|
+
return JSON.parse(readFileSync(ALERTS_FILE, 'utf-8'));
|
|
47
|
+
}
|
|
48
|
+
return { alerts: [] };
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function saveAlerts(data) {
|
|
52
|
+
writeFileSync(ALERTS_FILE, JSON.stringify(data, null, 2));
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const commands = {
|
|
56
|
+
properties: () => {
|
|
57
|
+
printHeader('Google Analytics Properties');
|
|
58
|
+
const result = pdauthCall('List ALL available Google Analytics properties I have access to. Show property names and IDs in a clean list format.');
|
|
59
|
+
console.log(result);
|
|
60
|
+
},
|
|
61
|
+
|
|
62
|
+
report: (property) => {
|
|
63
|
+
if (!property) {
|
|
64
|
+
console.log('Usage: ga report <property-name-or-id>');
|
|
65
|
+
process.exit(1);
|
|
66
|
+
}
|
|
67
|
+
printHeader(`30-Day Report: ${property}`);
|
|
68
|
+
const result = pdauthCall(`For property "${property}", get a comprehensive 30-day report showing: total users, new users, sessions, page views, and average session duration. Format as a clean summary with numbers.`);
|
|
69
|
+
console.log(result);
|
|
70
|
+
},
|
|
71
|
+
|
|
72
|
+
traffic: (property) => {
|
|
73
|
+
if (!property) {
|
|
74
|
+
console.log('Usage: ga traffic <property-name-or-id>');
|
|
75
|
+
process.exit(1);
|
|
76
|
+
}
|
|
77
|
+
printHeader(`Traffic Sources: ${property}`);
|
|
78
|
+
const result = pdauthCall(`For property "${property}", get sessions breakdown by traffic source (sessionSource) for the last 30 days. Show top 15 sources with users, sessions, and pageviews. Format as a table.`);
|
|
79
|
+
console.log(result);
|
|
80
|
+
},
|
|
81
|
+
|
|
82
|
+
devices: (property) => {
|
|
83
|
+
if (!property) {
|
|
84
|
+
console.log('Usage: ga devices <property-name-or-id>');
|
|
85
|
+
process.exit(1);
|
|
86
|
+
}
|
|
87
|
+
printHeader(`Device Breakdown: ${property}`);
|
|
88
|
+
const result = pdauthCall(`For property "${property}", get sessions breakdown by device category (desktop, mobile, tablet) for the last 30 days. Show users, sessions, and percentage for each.`);
|
|
89
|
+
console.log(result);
|
|
90
|
+
},
|
|
91
|
+
|
|
92
|
+
pages: (property) => {
|
|
93
|
+
if (!property) {
|
|
94
|
+
console.log('Usage: ga pages <property-name-or-id>');
|
|
95
|
+
process.exit(1);
|
|
96
|
+
}
|
|
97
|
+
printHeader(`Top Pages: ${property}`);
|
|
98
|
+
const result = pdauthCall(`For property "${property}", get the top 20 pages by pageviews for the last 30 days. Show page path, pageviews, and users.`);
|
|
99
|
+
console.log(result);
|
|
100
|
+
},
|
|
101
|
+
|
|
102
|
+
countries: (property) => {
|
|
103
|
+
if (!property) {
|
|
104
|
+
console.log('Usage: ga countries <property-name-or-id>');
|
|
105
|
+
process.exit(1);
|
|
106
|
+
}
|
|
107
|
+
printHeader(`Countries: ${property}`);
|
|
108
|
+
const result = pdauthCall(`For property "${property}", get sessions breakdown by country for the last 30 days. Show top 15 countries with users and sessions.`);
|
|
109
|
+
console.log(result);
|
|
110
|
+
},
|
|
111
|
+
|
|
112
|
+
compare: (property) => {
|
|
113
|
+
if (!property) {
|
|
114
|
+
console.log('Usage: ga compare <property-name-or-id>');
|
|
115
|
+
process.exit(1);
|
|
116
|
+
}
|
|
117
|
+
printHeader(`Period Comparison: ${property}`);
|
|
118
|
+
const result = pdauthCall(`For property "${property}", compare the last 30 days vs the previous 30 days. Show users, sessions, and pageviews for both periods with percentage change.`);
|
|
119
|
+
console.log(result);
|
|
120
|
+
},
|
|
121
|
+
|
|
122
|
+
franchise: () => {
|
|
123
|
+
printHeader('Hale Pet Door Franchise Overview');
|
|
124
|
+
console.log('Fetching data for all franchises (this may take a moment)...\n');
|
|
125
|
+
|
|
126
|
+
const franchises = [
|
|
127
|
+
{ name: 'Hale Pet Door (Main)', id: '494080031' },
|
|
128
|
+
{ name: 'HPD Orlando', id: '494128845' },
|
|
129
|
+
{ name: 'Denver', id: '398496582' },
|
|
130
|
+
{ name: 'Atlanta', id: '393738911' },
|
|
131
|
+
{ name: 'San Antonio', id: '392790632' },
|
|
132
|
+
{ name: 'Twin Cities', id: '392331022' },
|
|
133
|
+
{ name: 'Boise', id: '393448653' },
|
|
134
|
+
];
|
|
135
|
+
|
|
136
|
+
const result = pdauthCall(`Get a quick summary for these GA4 properties showing total users and sessions for the last 30 days: ${franchises.map(f => `${f.name} (ID: ${f.id})`).join(', ')}. Format as a comparison table.`);
|
|
137
|
+
console.log(result);
|
|
138
|
+
},
|
|
139
|
+
|
|
140
|
+
export: (property) => {
|
|
141
|
+
if (!property) {
|
|
142
|
+
console.log('Usage: ga export <property-name-or-id> [filename]');
|
|
143
|
+
process.exit(1);
|
|
144
|
+
}
|
|
145
|
+
const filename = `ga-export-${Date.now()}.csv`;
|
|
146
|
+
printHeader(`Exporting: ${property}`);
|
|
147
|
+
|
|
148
|
+
const result = pdauthCall(`For property "${property}", get the last 30 days data with: date, users, sessions, pageviews, bounceRate. Format the output as CSV with headers. One row per day.`);
|
|
149
|
+
|
|
150
|
+
// Try to extract CSV-like content
|
|
151
|
+
console.log('Raw data:\n');
|
|
152
|
+
console.log(result);
|
|
153
|
+
|
|
154
|
+
// Save to file
|
|
155
|
+
const filepath = join(process.cwd(), filename);
|
|
156
|
+
writeFileSync(filepath, result);
|
|
157
|
+
console.log(`\nā
Saved to: ${filepath}`);
|
|
158
|
+
},
|
|
159
|
+
|
|
160
|
+
'export-all': () => {
|
|
161
|
+
printHeader('Exporting All Properties');
|
|
162
|
+
const timestamp = new Date().toISOString().split('T')[0];
|
|
163
|
+
const filename = `ga-franchise-export-${timestamp}.csv`;
|
|
164
|
+
|
|
165
|
+
const result = pdauthCall(`For ALL Hale Pet Door properties I have access to, get total users and sessions for the last 30 days. Format as CSV with columns: property_name, property_id, users, sessions. Include all 22 properties.`);
|
|
166
|
+
|
|
167
|
+
console.log(result);
|
|
168
|
+
|
|
169
|
+
const filepath = join(process.cwd(), filename);
|
|
170
|
+
writeFileSync(filepath, result);
|
|
171
|
+
console.log(`\nā
Saved to: ${filepath}`);
|
|
172
|
+
},
|
|
173
|
+
|
|
174
|
+
'alert-add': (args) => {
|
|
175
|
+
const parts = args.split(' ');
|
|
176
|
+
if (parts.length < 3) {
|
|
177
|
+
console.log('Usage: ga alert-add <property> <metric> <threshold>');
|
|
178
|
+
console.log('Example: ga alert-add 494080031 users-drop 20%');
|
|
179
|
+
console.log('Example: ga alert-add "Hale Pet Door" sessions-below 100');
|
|
180
|
+
process.exit(1);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
const threshold = parts.pop();
|
|
184
|
+
const metric = parts.pop();
|
|
185
|
+
const property = parts.join(' ');
|
|
186
|
+
|
|
187
|
+
const data = loadAlerts();
|
|
188
|
+
const alert = {
|
|
189
|
+
id: Date.now(),
|
|
190
|
+
property,
|
|
191
|
+
metric,
|
|
192
|
+
threshold,
|
|
193
|
+
created: new Date().toISOString(),
|
|
194
|
+
enabled: true
|
|
195
|
+
};
|
|
196
|
+
data.alerts.push(alert);
|
|
197
|
+
saveAlerts(data);
|
|
198
|
+
|
|
199
|
+
printHeader('Alert Created');
|
|
200
|
+
console.log(` Property: ${property}`);
|
|
201
|
+
console.log(` Metric: ${metric}`);
|
|
202
|
+
console.log(` Threshold: ${threshold}`);
|
|
203
|
+
console.log(` ID: ${alert.id}`);
|
|
204
|
+
console.log('\nā
Alert saved! Run "ga alert-check" to test.');
|
|
205
|
+
},
|
|
206
|
+
|
|
207
|
+
'alert-list': () => {
|
|
208
|
+
printHeader('Configured Alerts');
|
|
209
|
+
const data = loadAlerts();
|
|
210
|
+
|
|
211
|
+
if (data.alerts.length === 0) {
|
|
212
|
+
console.log('No alerts configured.');
|
|
213
|
+
console.log('Run: ga alert-add <property> <metric> <threshold>');
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
data.alerts.forEach((alert, i) => {
|
|
218
|
+
const status = alert.enabled ? 'ā
' : 'ā';
|
|
219
|
+
console.log(`${i + 1}. ${status} ${alert.property}`);
|
|
220
|
+
console.log(` Metric: ${alert.metric} | Threshold: ${alert.threshold}`);
|
|
221
|
+
console.log(` ID: ${alert.id}`);
|
|
222
|
+
console.log('');
|
|
223
|
+
});
|
|
224
|
+
},
|
|
225
|
+
|
|
226
|
+
'alert-check': () => {
|
|
227
|
+
printHeader('Checking Alerts');
|
|
228
|
+
const data = loadAlerts();
|
|
229
|
+
|
|
230
|
+
if (data.alerts.length === 0) {
|
|
231
|
+
console.log('No alerts to check.');
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
data.alerts.filter(a => a.enabled).forEach(alert => {
|
|
236
|
+
console.log(`\nš Checking: ${alert.property} (${alert.metric} ${alert.threshold})`);
|
|
237
|
+
|
|
238
|
+
const result = pdauthCall(`For property "${alert.property}", check if ${alert.metric} has crossed threshold ${alert.threshold} in the last 7 days compared to previous 7 days. Give a brief YES/NO answer with the actual numbers.`);
|
|
239
|
+
|
|
240
|
+
console.log(result);
|
|
241
|
+
});
|
|
242
|
+
},
|
|
243
|
+
|
|
244
|
+
'alert-remove': (id) => {
|
|
245
|
+
if (!id) {
|
|
246
|
+
console.log('Usage: ga alert-remove <alert-id>');
|
|
247
|
+
process.exit(1);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
const data = loadAlerts();
|
|
251
|
+
const before = data.alerts.length;
|
|
252
|
+
data.alerts = data.alerts.filter(a => String(a.id) !== String(id));
|
|
253
|
+
|
|
254
|
+
if (data.alerts.length === before) {
|
|
255
|
+
console.log(`Alert ${id} not found.`);
|
|
256
|
+
process.exit(1);
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
saveAlerts(data);
|
|
260
|
+
console.log(`ā
Alert ${id} removed.`);
|
|
261
|
+
},
|
|
262
|
+
|
|
263
|
+
realtime: (property) => {
|
|
264
|
+
if (!property) {
|
|
265
|
+
console.log('Usage: ga realtime <property>');
|
|
266
|
+
process.exit(1);
|
|
267
|
+
}
|
|
268
|
+
printHeader(`Realtime: ${property}`);
|
|
269
|
+
console.log('ā ļø Note: GA4 realtime requires special API access.');
|
|
270
|
+
const result = pdauthCall(`For property "${property}", get the most recent data available - today's users and sessions if possible, otherwise the last 24 hours.`);
|
|
271
|
+
console.log(result);
|
|
272
|
+
},
|
|
273
|
+
|
|
274
|
+
help: () => {
|
|
275
|
+
console.log(`
|
|
276
|
+
š ga - Google Analytics CLI
|
|
277
|
+
|
|
278
|
+
USAGE:
|
|
279
|
+
ga <command> [property]
|
|
280
|
+
|
|
281
|
+
COMMANDS:
|
|
282
|
+
properties List all available properties
|
|
283
|
+
report <prop> 30-day overview (users, sessions, pageviews)
|
|
284
|
+
traffic <prop> Traffic sources breakdown
|
|
285
|
+
devices <prop> Desktop vs Mobile vs Tablet
|
|
286
|
+
pages <prop> Top pages by views
|
|
287
|
+
countries <prop> Geographic breakdown
|
|
288
|
+
compare <prop> This month vs last month
|
|
289
|
+
franchise Hale Pet Door network overview
|
|
290
|
+
realtime <prop> Today/last 24h snapshot
|
|
291
|
+
|
|
292
|
+
EXPORT:
|
|
293
|
+
export <prop> Export 30 days to CSV
|
|
294
|
+
export-all Export all franchises to CSV
|
|
295
|
+
|
|
296
|
+
ALERTS:
|
|
297
|
+
alert-add <prop> <metric> <threshold> Add alert
|
|
298
|
+
alert-list List all alerts
|
|
299
|
+
alert-check Check all alerts now
|
|
300
|
+
alert-remove <id> Remove an alert
|
|
301
|
+
|
|
302
|
+
EXAMPLES:
|
|
303
|
+
ga properties
|
|
304
|
+
ga report "Hale Pet Door"
|
|
305
|
+
ga traffic 494080031
|
|
306
|
+
ga franchise
|
|
307
|
+
ga export "HPD-Orlando"
|
|
308
|
+
ga alert-add "Hale Pet Door" users-drop 20%
|
|
309
|
+
ga alert-check
|
|
310
|
+
|
|
311
|
+
PROPERTY:
|
|
312
|
+
Can be name ("Hale Pet Door") or ID (494080031)
|
|
313
|
+
`);
|
|
314
|
+
}
|
|
315
|
+
};
|
|
316
|
+
|
|
317
|
+
// Parse args
|
|
318
|
+
const [,, command, ...rest] = process.argv;
|
|
319
|
+
const property = rest.join(' ');
|
|
320
|
+
|
|
321
|
+
if (!command || command === 'help' || command === '--help' || command === '-h') {
|
|
322
|
+
commands.help();
|
|
323
|
+
} else if (commands[command]) {
|
|
324
|
+
commands[command](property);
|
|
325
|
+
} else {
|
|
326
|
+
console.log(`Unknown command: ${command}`);
|
|
327
|
+
console.log('Run "ga help" for usage');
|
|
328
|
+
process.exit(1);
|
|
329
|
+
}
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
|