@supalytics/cli 0.3.0 → 0.3.2

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/README.md CHANGED
@@ -117,11 +117,12 @@ All commands support:
117
117
  ## Site Management
118
118
 
119
119
  ```bash
120
- supalytics sites # List all sites
121
- supalytics sites add # Create a new site
122
- supalytics sites update # Update site settings
123
- supalytics default <domain> # Set default site
124
- supalytics stats -s other.com # Query specific site
120
+ supalytics sites # List all sites
121
+ supalytics sites add example.com # Create site with domain
122
+ supalytics sites add my-project # Or use any name, update later
123
+ supalytics sites update my-project -d example.com # Set the real domain
124
+ supalytics default example.com # Set default site
125
+ supalytics stats -s other.com # Query specific site
125
126
  ```
126
127
 
127
128
  ## Shell Completions
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@supalytics/cli",
3
- "version": "0.3.0",
3
+ "version": "0.3.2",
4
4
  "description": "CLI for Supalytics web analytics",
5
5
  "type": "module",
6
6
  "bin": {
package/src/api.ts CHANGED
@@ -88,10 +88,10 @@ export async function query(
88
88
 
89
89
  export function formatNumber(num: number): string {
90
90
  if (num >= 1_000_000) {
91
- return (num / 1_000_000).toFixed(1) + "M";
91
+ return (num / 1_000_000).toFixed(2) + "M";
92
92
  }
93
93
  if (num >= 1_000) {
94
- return (num / 1_000).toFixed(1) + "K";
94
+ return (num / 1_000).toFixed(2) + "K";
95
95
  }
96
96
  return num.toString();
97
97
  }
@@ -128,12 +128,31 @@ async function syncSites(accessToken: string): Promise<SyncSite[]> {
128
128
  return data.sites;
129
129
  }
130
130
 
131
- export async function loginWithDeviceFlow(): Promise<void> {
131
+ export async function loginWithDeviceFlow(forceResync = false): Promise<void> {
132
132
  // Check if already logged in
133
133
  const existingAuth = await getAuth();
134
- if (existingAuth) {
134
+ if (existingAuth && !forceResync) {
135
135
  console.log(chalk.dim(`Already logged in as ${existingAuth.email}`));
136
- console.log(chalk.dim(`Run 'supalytics logout' to log out first.`));
136
+ console.log(chalk.dim(`Run 'supalytics login --resync' to refresh API keys, or 'supalytics logout' to log out.`));
137
+ return;
138
+ }
139
+
140
+ // If resyncing, just sync sites with existing auth
141
+ if (existingAuth && forceResync) {
142
+ console.log(chalk.dim("Resyncing sites..."));
143
+ try {
144
+ const sites = await syncSites(existingAuth.accessToken);
145
+ if (sites.length > 0) {
146
+ for (const { site, apiKey } of sites) {
147
+ await addSiteWithId(site.domain, apiKey.key, site.site_id, site.id);
148
+ }
149
+ console.log(chalk.green(`✓ Synced ${sites.length} site${sites.length > 1 ? "s" : ""}`));
150
+ } else {
151
+ console.log(chalk.dim("No sites found."));
152
+ }
153
+ } catch {
154
+ console.log(chalk.yellow("Could not sync. Your session may have expired. Run 'supalytics logout' then 'supalytics login'."));
155
+ }
137
156
  return;
138
157
  }
139
158
 
@@ -197,9 +216,10 @@ export async function loginWithDeviceFlow(): Promise<void> {
197
216
 
198
217
  export const loginCommand = new Command("login")
199
218
  .description("Authenticate with Supalytics")
200
- .action(async () => {
219
+ .option("--resync", "Refresh API keys for all sites")
220
+ .action(async (options: { resync?: boolean }) => {
201
221
  try {
202
- await loginWithDeviceFlow();
222
+ await loginWithDeviceFlow(options.resync || false);
203
223
  } catch (error) {
204
224
  console.error(chalk.red(`Error: ${(error as Error).message}`));
205
225
  process.exit(1);