← 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 →