flake-update-20260505
  1#!/usr/bin/env node
  2
  3import {
  4  CREDENTIALS_PATH,
  5  TOKEN_PATH,
  6  DEFAULT_SCOPES,
  7  authorize,
  8  clearToken,
  9  credentialsExist,
 10  formatScopes,
 11  loadToken,
 12} from "./common.js";
 13
 14function printHelp() {
 15  console.log(`Google Workspace auth helper
 16
 17Usage:
 18  node auth.js login [--scopes scope1,scope2,...]
 19  node auth.js status
 20  node auth.js clear
 21
 22Environment overrides:
 23  GOOGLE_WORKSPACE_CONFIG_DIR
 24  GOOGLE_WORKSPACE_CREDENTIALS
 25  GOOGLE_WORKSPACE_TOKEN
 26`);
 27}
 28
 29function parseScopes(args) {
 30  const idx = args.indexOf("--scopes");
 31  if (idx === -1) {
 32    return DEFAULT_SCOPES;
 33  }
 34  const raw = args[idx + 1];
 35  if (!raw) {
 36    throw new Error("--scopes requires a value");
 37  }
 38  const scopes = formatScopes(raw);
 39  if (scopes.length === 0) {
 40    throw new Error("--scopes produced an empty scope list");
 41  }
 42  return scopes;
 43}
 44
 45async function doLogin(args) {
 46  const scopes = parseScopes(args);
 47  await authorize({ scopes, interactive: true });
 48  console.log("✅ Login successful. Token stored at:");
 49  console.log(`   ${TOKEN_PATH}`);
 50}
 51
 52function doStatus() {
 53  console.log("Credentials file:");
 54  console.log(`  ${CREDENTIALS_PATH}`);
 55  console.log(`  Exists: ${credentialsExist() ? "yes" : "no"}`);
 56
 57  const token = loadToken();
 58
 59  console.log("\nToken file:");
 60  console.log(`  ${TOKEN_PATH}`);
 61  console.log(`  Exists: ${token ? "yes" : "no"}`);
 62
 63  if (!token) {
 64    return;
 65  }
 66
 67  const now = Date.now();
 68  const expiry = token.expiry_date || null;
 69  const expired = expiry ? expiry < now : null;
 70  const scopeCount = formatScopes(token.scope).length;
 71
 72  console.log("\nToken details:");
 73  console.log(`  access_token: ${token.access_token ? "present" : "missing"}`);
 74  console.log(
 75    `  refresh_token: ${token.refresh_token ? "present" : "missing"}`
 76  );
 77  console.log(`  scopes: ${scopeCount}`);
 78
 79  if (expiry) {
 80    console.log(`  expiry_date: ${new Date(expiry).toISOString()}`);
 81    console.log(`  expired: ${expired ? "yes" : "no"}`);
 82  } else {
 83    console.log("  expiry_date: n/a");
 84  }
 85}
 86
 87function doClear() {
 88  clearToken();
 89  console.log("✅ Token cleared.");
 90}
 91
 92async function main() {
 93  const [command, ...args] = process.argv.slice(2);
 94
 95  if (
 96    !command ||
 97    command === "help" ||
 98    command === "--help" ||
 99    command === "-h"
100  ) {
101    printHelp();
102    return;
103  }
104
105  if (command === "login") {
106    await doLogin(args);
107    return;
108  }
109
110  if (command === "status") {
111    doStatus();
112    return;
113  }
114
115  if (command === "clear") {
116    doClear();
117    return;
118  }
119
120  throw new Error(`Unknown command: ${command}`);
121}
122
123main().catch((error) => {
124  console.error(`${error.message}`);
125  process.exit(1);
126});