[object Object]

← back to Ga4 Fleet

provision.mjs: accept GA4_TOKEN (your gcloud login, no key needed) + always scan all accounts for dedup

c2b363e0a359526ae7ae3e679ec28aaa79b372ed · 2026-08-03 14:20:41 -0700 · Steve

Files touched

Diff

commit c2b363e0a359526ae7ae3e679ec28aaa79b372ed
Author: Steve <steve@designerwallcoverings.com>
Date:   Mon Aug 3 14:20:41 2026 -0700

    provision.mjs: accept GA4_TOKEN (your gcloud login, no key needed) + always scan all accounts for dedup
---
 provision.mjs | 22 ++++++++++++----------
 1 file changed, 12 insertions(+), 10 deletions(-)

diff --git a/provision.mjs b/provision.mjs
index 8d9a780..2db095c 100644
--- a/provision.mjs
+++ b/provision.mjs
@@ -28,17 +28,16 @@ const COMMIT = has('--commit');
 const ACCOUNT = val('--account', null); // e.g. accounts/15714274 ; null = auto-list first accessible
 const LIMIT = Number(val('--limit', '0')) || Infinity;
 
-// ---- SA key: EXPLICIT only. No discovery, no scanning. The operator sets GA4_SA_KEY. ----
-function keyPath() {
-  const p = process.env.GA4_SA_KEY;
-  if (!p || !existsSync(p)) throw new Error('Set GA4_SA_KEY=/path/to/your/service-account-key.json before running.');
-  return p;
-}
-
-// ---- SA JWT -> access token ----
+// ---- Auth: SIMPLEST first. If GA4_TOKEN is set (your own gcloud access token), use it
+// directly — no service account, no key file. You already own the GA4 accounts, so:
+//   GA4_TOKEN=$(gcloud auth print-access-token) node provision.mjs ...
+// Fallback: GA4_SA_KEY=/path/key.json for a service-account key (JWT), if you prefer that.
 function b64url(buf) { return Buffer.from(buf).toString('base64').replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, ''); }
 async function getToken() {
-  const key = JSON.parse(readFileSync(keyPath(), 'utf8'));
+  if (process.env.GA4_TOKEN) return process.env.GA4_TOKEN;   // your gcloud login token — simplest path
+  const p = process.env.GA4_SA_KEY;
+  if (!p || !existsSync(p)) throw new Error('Set GA4_TOKEN=$(gcloud auth print-access-token) — or GA4_SA_KEY=/path/key.json for a service account.');
+  const key = JSON.parse(readFileSync(p, 'utf8'));
   const now = Math.floor(Date.now() / 1000);
   const header = b64url(JSON.stringify({ alg: 'RS256', typ: 'JWT' }));
   const claim = b64url(JSON.stringify({
@@ -70,7 +69,10 @@ async function api(path, method = 'GET', body) {
 // ---- existing coverage: domain -> measurementId across all visible streams ----
 async function existingByDomain() {
   const map = {};
-  const accts = ACCOUNT ? [{ name: ACCOUNT }] : (await api('accounts')).accounts || [];
+  // ALWAYS scan every accessible account for the existence check — a domain's property may
+  // live under a different account than --account (which only sets where NEW ones get created).
+  // Scoping this to --account is how you mint a duplicate of a property that already exists elsewhere.
+  const accts = (await api('accounts')).accounts || [];
   for (const a of accts) {
     let pageToken;
     do {

← 0f6cff8 GA4: STOP grind — celebrity already had G-2HEVP6TD0J (repo-m  ·  back to Ga4 Fleet  ·  GA4: 32 truly-missing sites (live-checked; celebrity/prestig 2dee8b5 →