sfc-utils 1.4.209 → 1.4.211
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/components/layout/layoutscript.mjs +1 -3
- package/copy/c2p_sheet.js +74 -97
- package/copy/docs.js +7 -16
- package/copy/googleauth.js +3 -114
- package/copy/sheets.js +9 -23
- package/package.json +1 -2
- package/.playwright-mcp/console-2026-04-02T20-52-32-578Z.log +0 -994
- package/.playwright-mcp/page-2026-04-02T20-52-43-138Z.yml +0 -13584
- package/.playwright-mcp/page-2026-04-02T20-52-52-183Z.png +0 -0
|
@@ -42,9 +42,7 @@ const LayoutScript = ({ domain, marketingVer = 1 }) => {
|
|
|
42
42
|
{marketingVer === 1 && (
|
|
43
43
|
<script src="https://projects.sfchronicle.com/shared/js/jquery.min.js"></script>
|
|
44
44
|
)}
|
|
45
|
-
|
|
46
|
-
<script src="https://treg.hearstnp.com/treg.js"></script>
|
|
47
|
-
)}
|
|
45
|
+
<script src="https://treg.hearstnp.com/treg.js"></script>
|
|
48
46
|
</>
|
|
49
47
|
);
|
|
50
48
|
};
|
package/copy/c2p_sheet.js
CHANGED
|
@@ -18,54 +18,42 @@ var path = require("path");
|
|
|
18
18
|
|
|
19
19
|
let googleAuth = (configData) => {
|
|
20
20
|
var auth = null;
|
|
21
|
-
authObj
|
|
22
|
-
.authenticate(
|
|
21
|
+
return authObj
|
|
22
|
+
.authenticate()
|
|
23
23
|
.then((resp) => {
|
|
24
24
|
auth = resp;
|
|
25
|
-
createSheet(auth,
|
|
26
|
-
// If the first attempt failed, then make another req using the fallback
|
|
27
|
-
authObj.authenticate({ fallback: true }).then((resp) => {
|
|
28
|
-
auth = resp;
|
|
29
|
-
createSheet(auth, true, configData);
|
|
30
|
-
});
|
|
31
|
-
});
|
|
25
|
+
return createSheet(auth, configData);
|
|
32
26
|
})
|
|
33
|
-
.catch(() => {
|
|
34
|
-
|
|
35
|
-
auth = authObj.task();
|
|
36
|
-
createSheet(auth, true, configData);
|
|
27
|
+
.catch((err) => {
|
|
28
|
+
throw err;
|
|
37
29
|
});
|
|
38
30
|
};
|
|
39
31
|
|
|
40
|
-
let createSheet = (auth,
|
|
32
|
+
let createSheet = (auth, configData) => {
|
|
41
33
|
return new Promise((resolveAll, rejectAll) => {
|
|
42
34
|
let gmail;
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
console.log("'gmail' is blank in credentials file!");
|
|
58
|
-
rejectAll();
|
|
59
|
-
return;
|
|
60
|
-
}
|
|
35
|
+
try {
|
|
36
|
+
let credsLocation = path.join(os.homedir(), ".credentials.json");
|
|
37
|
+
let credsData = JSON.parse(fs.readFileSync(credsLocation, "utf-8"));
|
|
38
|
+
gmail = credsData.gmail;
|
|
39
|
+
} catch (err) {
|
|
40
|
+
// If we had any trouble getting the gmail address, fail out
|
|
41
|
+
console.log(err);
|
|
42
|
+
rejectAll(err);
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
if (!gmail) {
|
|
46
|
+
// If gmail is blank, fail out
|
|
47
|
+
rejectAll(new Error("'gmail' is blank in credentials file!"));
|
|
48
|
+
return;
|
|
61
49
|
}
|
|
62
50
|
|
|
63
51
|
const drive = google.drive({ version: "v3", auth });
|
|
64
52
|
const templateId = "1DUvYnFdxtBv1AXcDI9X00s_opUSu4uHJmd5LNemCN9E";
|
|
65
53
|
const body = { title: "New C2P sheet", name: configData.PROJECT.SLUG };
|
|
66
|
-
if (configData.PROJECT.MARKET_KEY === "SFC"){
|
|
54
|
+
if (configData.PROJECT.MARKET_KEY === "SFC") {
|
|
67
55
|
// If this is SFC, make sure it's created in the shared folder
|
|
68
|
-
body.parents = [
|
|
56
|
+
body.parents = ["1_jnRs3xOYDxm27y7TZB9gkudzTRmcd7x"];
|
|
69
57
|
}
|
|
70
58
|
const createOptions = {
|
|
71
59
|
fileId: templateId, // Base template
|
|
@@ -76,6 +64,12 @@ let createSheet = (auth, fallback, configData) => {
|
|
|
76
64
|
drive.files.copy(
|
|
77
65
|
createOptions,
|
|
78
66
|
(err, resp) => {
|
|
67
|
+
if (err) {
|
|
68
|
+
console.log("An error prevented the creation of this sheet!");
|
|
69
|
+
rejectAll(err);
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
|
|
79
73
|
// Make edits to the sheet to match the repo details
|
|
80
74
|
let resources = {
|
|
81
75
|
auth: auth,
|
|
@@ -116,71 +110,54 @@ let createSheet = (auth, fallback, configData) => {
|
|
|
116
110
|
writeFile("project-config.json", JSON.stringify(configData, null, 2));
|
|
117
111
|
|
|
118
112
|
// Okay, now give the team permissions
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
}
|
|
162
|
-
drive.permissions.create(
|
|
163
|
-
{
|
|
164
|
-
resource: permission2,
|
|
165
|
-
fileId: resp.data.id, // Modify the created file
|
|
166
|
-
},
|
|
167
|
-
(permErr, permResp) => {
|
|
168
|
-
if (permErr) {
|
|
169
|
-
console.log("An error prevented the sharing of this sheet with the service account!");
|
|
170
|
-
rejectAll();
|
|
171
|
-
} else {
|
|
172
|
-
console.log(
|
|
173
|
-
`Sheet also shared with service account for quick deploying!`
|
|
174
|
-
);
|
|
175
|
-
resolveAll();
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
)
|
|
113
|
+
const permission = {
|
|
114
|
+
type: "user",
|
|
115
|
+
role: "writer",
|
|
116
|
+
emailAddress: gmail,
|
|
117
|
+
};
|
|
118
|
+
drive.permissions.create(
|
|
119
|
+
{
|
|
120
|
+
resource: permission,
|
|
121
|
+
fileId: resp.data.id, // Modify the created file
|
|
122
|
+
},
|
|
123
|
+
(permErr, permResp) => {
|
|
124
|
+
if (permErr) {
|
|
125
|
+
console.log("An error prevented the sharing of this sheet!");
|
|
126
|
+
rejectAll(permErr);
|
|
127
|
+
} else {
|
|
128
|
+
console.log(
|
|
129
|
+
"Your new C2P sheet should be live at this URL:",
|
|
130
|
+
`https://docs.google.com/spreadsheets/d/${resp.data.id}/edit`
|
|
131
|
+
);
|
|
132
|
+
console.log(
|
|
133
|
+
`NOTE: It may take a few seconds before your gmail, ${gmail}, has access`
|
|
134
|
+
);
|
|
135
|
+
// Now share with the service account
|
|
136
|
+
const permission2 = {
|
|
137
|
+
type: "user",
|
|
138
|
+
role: "writer",
|
|
139
|
+
emailAddress: "sfchronicle-gatsby@zinc-proton-250521.iam.gserviceaccount.com",
|
|
140
|
+
};
|
|
141
|
+
drive.permissions.create(
|
|
142
|
+
{
|
|
143
|
+
resource: permission2,
|
|
144
|
+
fileId: resp.data.id, // Modify the created file
|
|
145
|
+
},
|
|
146
|
+
(permErr, permResp) => {
|
|
147
|
+
if (permErr) {
|
|
148
|
+
console.log("An error prevented the sharing of this sheet with the service account!");
|
|
149
|
+
rejectAll(permErr);
|
|
150
|
+
} else {
|
|
151
|
+
console.log(
|
|
152
|
+
`Sheet also shared with service account for quick deploying!`
|
|
153
|
+
);
|
|
154
|
+
resolveAll();
|
|
155
|
+
}
|
|
179
156
|
}
|
|
180
|
-
|
|
181
|
-
|
|
157
|
+
)
|
|
158
|
+
}
|
|
182
159
|
}
|
|
183
|
-
|
|
160
|
+
);
|
|
184
161
|
}
|
|
185
162
|
);
|
|
186
163
|
});
|
package/copy/docs.js
CHANGED
|
@@ -21,22 +21,14 @@ var Entities = require("html-entities").AllHtmlEntities;
|
|
|
21
21
|
|
|
22
22
|
let googleAuth = (config, directory = null, filenames = null, useID = null) => {
|
|
23
23
|
var auth = null;
|
|
24
|
-
authObj
|
|
25
|
-
.authenticate(
|
|
24
|
+
return authObj
|
|
25
|
+
.authenticate()
|
|
26
26
|
.then((resp) => {
|
|
27
27
|
auth = resp;
|
|
28
|
-
grabDocs(auth, config, directory, filenames, useID)
|
|
29
|
-
// If the first attempt failed, then make another req using the fallback
|
|
30
|
-
authObj.authenticate({ fallback: true }).then((resp) => {
|
|
31
|
-
auth = resp;
|
|
32
|
-
grabDocs(auth, config, directory, filenames, useID);
|
|
33
|
-
});
|
|
34
|
-
});
|
|
28
|
+
return grabDocs(auth, config, directory, filenames, useID);
|
|
35
29
|
})
|
|
36
|
-
.catch(() => {
|
|
37
|
-
|
|
38
|
-
auth = authObj.task();
|
|
39
|
-
grabDocs(auth, config, directory, filenames, useID);
|
|
30
|
+
.catch((err) => {
|
|
31
|
+
throw err;
|
|
40
32
|
});
|
|
41
33
|
};
|
|
42
34
|
|
|
@@ -72,9 +64,8 @@ let grabDocs = (
|
|
|
72
64
|
.get({
|
|
73
65
|
fileId,
|
|
74
66
|
})
|
|
75
|
-
.catch(() => {
|
|
76
|
-
|
|
77
|
-
reject();
|
|
67
|
+
.catch((err) => {
|
|
68
|
+
reject(err);
|
|
78
69
|
});
|
|
79
70
|
if (!meta) {
|
|
80
71
|
return;
|
package/copy/googleauth.js
CHANGED
|
@@ -1,64 +1,20 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
var { google } = require("googleapis");
|
|
4
|
-
var opn = require("opn");
|
|
5
4
|
|
|
6
|
-
var http = require("http");
|
|
7
5
|
var os = require("os");
|
|
8
6
|
var path = require("path");
|
|
9
|
-
var url = require("url");
|
|
10
7
|
var fs = require("fs");
|
|
11
|
-
var writeFile = require("write");
|
|
12
8
|
|
|
13
9
|
// Prep the service account for drive
|
|
14
10
|
var serviceAccountCreds = path.join(
|
|
15
11
|
os.homedir(),
|
|
16
12
|
"service-account-google-creds.json"
|
|
17
13
|
);
|
|
18
|
-
var tokenLocation = path.join(os.homedir(), ".google_oauth_token");
|
|
19
14
|
|
|
20
|
-
var
|
|
21
|
-
// If it's coming from EC2, pull from project
|
|
22
|
-
if (process.env.GOOGLE_OAUTH_SYSTEM === "EC2") {
|
|
23
|
-
tokenLocation = "../.google_oauth_token";
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
try {
|
|
27
|
-
var tokens = fs.readFileSync(tokenLocation, "utf-8");
|
|
28
|
-
tokens = JSON.parse(tokens);
|
|
29
|
-
auth = new google.auth.OAuth2(
|
|
30
|
-
process.env.GOOGLE_OAUTH_CLIENT_ID,
|
|
31
|
-
process.env.GOOGLE_OAUTH_CONSUMER_SECRET
|
|
32
|
-
);
|
|
33
|
-
auth.setCredentials(tokens);
|
|
34
|
-
|
|
35
|
-
auth.on("tokens", function (update) {
|
|
36
|
-
Object.assign(tokens, update);
|
|
37
|
-
fs.writeFileSync(tokenLocation, JSON.stringify(tokens, null, 2));
|
|
38
|
-
});
|
|
39
|
-
} catch (err) {
|
|
40
|
-
// If we error here, fire up local (as long as we're on on EC2)
|
|
41
|
-
if (process.env.GOOGLE_OAUTH_SYSTEM !== "EC2") {
|
|
42
|
-
task();
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
return auth;
|
|
46
|
-
};
|
|
47
|
-
|
|
48
|
-
var authenticate = function ({ fallback }) {
|
|
15
|
+
var authenticate = function () {
|
|
49
16
|
console.log("\n========== GOOGLEAUTH: authenticate() called ==========");
|
|
50
|
-
console.log("GOOGLEAUTH: fallback parameter =", fallback);
|
|
51
17
|
|
|
52
|
-
if (fallback) {
|
|
53
|
-
return new Promise((resolve, reject) => {
|
|
54
|
-
console.log("GOOGLEAUTH: Using fallback auth path");
|
|
55
|
-
console.log(
|
|
56
|
-
"Service account failed, falling back to regular token (to use the service account, share this sheet or doc with sfchronicle-gatsby@zinc-proton-250521.iam.gserviceaccount.com)"
|
|
57
|
-
);
|
|
58
|
-
resolve(fallbackAuth());
|
|
59
|
-
});
|
|
60
|
-
}
|
|
61
|
-
// Try to use the service account first
|
|
62
18
|
return new Promise((resolve, reject) => {
|
|
63
19
|
try {
|
|
64
20
|
console.log("GOOGLEAUTH: Attempting service account authentication...");
|
|
@@ -96,7 +52,7 @@ var authenticate = function ({ fallback }) {
|
|
|
96
52
|
if (err) {
|
|
97
53
|
console.log("GOOGLEAUTH: Stage 1 error during jwtClient.authorize()");
|
|
98
54
|
console.log("GOOGLEAUTH: Error details:", err.message || err);
|
|
99
|
-
|
|
55
|
+
reject(err);
|
|
100
56
|
} else {
|
|
101
57
|
console.log("Successfully connected to service account!");
|
|
102
58
|
console.log(
|
|
@@ -112,81 +68,14 @@ var authenticate = function ({ fallback }) {
|
|
|
112
68
|
}
|
|
113
69
|
});
|
|
114
70
|
} catch (err) {
|
|
115
|
-
// It's ok if it errors, we have the fallback
|
|
116
71
|
console.log("GOOGLEAUTH: Stage 2 error (catch block)");
|
|
117
72
|
console.log("GOOGLEAUTH: Error details:", err.message || err);
|
|
118
|
-
|
|
73
|
+
reject(err);
|
|
119
74
|
}
|
|
120
75
|
});
|
|
121
76
|
};
|
|
122
77
|
|
|
123
|
-
var task = function () {
|
|
124
|
-
// var done = this.async();
|
|
125
|
-
|
|
126
|
-
var clientID = process.env.GOOGLE_OAUTH_CLIENT_ID;
|
|
127
|
-
var secret = process.env.GOOGLE_OAUTH_CONSUMER_SECRET;
|
|
128
|
-
|
|
129
|
-
var client = new google.auth.OAuth2(
|
|
130
|
-
clientID,
|
|
131
|
-
secret,
|
|
132
|
-
"http://localhost:8000/authenticate/"
|
|
133
|
-
);
|
|
134
|
-
google.options({
|
|
135
|
-
auth: client,
|
|
136
|
-
});
|
|
137
|
-
|
|
138
|
-
var scopes = [
|
|
139
|
-
"https://www.googleapis.com/auth/drive",
|
|
140
|
-
"https://www.googleapis.com/auth/spreadsheets",
|
|
141
|
-
];
|
|
142
|
-
|
|
143
|
-
var authURL = client.generateAuthUrl({
|
|
144
|
-
access_type: "offline",
|
|
145
|
-
scope: scopes.join(" "),
|
|
146
|
-
prompt: "consent",
|
|
147
|
-
});
|
|
148
|
-
|
|
149
|
-
var onRequest = function (request, response) {
|
|
150
|
-
response.setHeader("Connection", "close");
|
|
151
|
-
if (request.url.indexOf("authenticate") > -1) {
|
|
152
|
-
return onAuthenticated(request, response);
|
|
153
|
-
} else if (request.url.indexOf("authorize") > -1) {
|
|
154
|
-
response.setHeader("Location", authURL);
|
|
155
|
-
response.writeHead(302);
|
|
156
|
-
} else {
|
|
157
|
-
response.writeHead(404);
|
|
158
|
-
}
|
|
159
|
-
response.end();
|
|
160
|
-
};
|
|
161
|
-
|
|
162
|
-
var onAuthenticated = async function (request, response) {
|
|
163
|
-
var requestURL =
|
|
164
|
-
request.url[0] == "/" ? "localhost:8000" + request.url : request.url;
|
|
165
|
-
var query = new url.URL(requestURL).searchParams;
|
|
166
|
-
var code = query.get("code");
|
|
167
|
-
if (!code) return;
|
|
168
|
-
try {
|
|
169
|
-
var token = await client.getToken(code);
|
|
170
|
-
var tokens = token.tokens;
|
|
171
|
-
writeFile(tokenLocation, JSON.stringify(tokens, null, 2), function (err) {
|
|
172
|
-
if (err) {
|
|
173
|
-
console.log(err);
|
|
174
|
-
} else {
|
|
175
|
-
console.log("Authenticated");
|
|
176
|
-
}
|
|
177
|
-
});
|
|
178
|
-
response.end("Done! Now run your command again.");
|
|
179
|
-
} catch (err) {
|
|
180
|
-
response.end(err);
|
|
181
|
-
}
|
|
182
|
-
};
|
|
183
|
-
|
|
184
|
-
var server = http.createServer(onRequest);
|
|
185
|
-
server.listen(8000, () => opn("http://localhost:8000/authorize"));
|
|
186
|
-
};
|
|
187
|
-
|
|
188
78
|
let fullAuth = {
|
|
189
|
-
task: task,
|
|
190
79
|
authenticate: authenticate,
|
|
191
80
|
};
|
|
192
81
|
module.exports = fullAuth;
|
package/copy/sheets.js
CHANGED
|
@@ -37,31 +37,17 @@ var cast = function (str, forceStr) {
|
|
|
37
37
|
};
|
|
38
38
|
|
|
39
39
|
let googleAuth = (project, directory = null, forceStr = false, options = {}) => {
|
|
40
|
-
return new Promise((resolveFinal) => {
|
|
40
|
+
return new Promise((resolveFinal, rejectFinal) => {
|
|
41
41
|
var auth = null;
|
|
42
42
|
authObj
|
|
43
|
-
.authenticate(
|
|
43
|
+
.authenticate()
|
|
44
44
|
.then((resp) => {
|
|
45
45
|
auth = resp;
|
|
46
46
|
grabSheets(auth, project, directory, forceStr, options)
|
|
47
47
|
.then(() => resolveFinal())
|
|
48
|
-
.catch(() =>
|
|
49
|
-
// If the first attempt failed, then make another req using the fallback
|
|
50
|
-
authObj.authenticate({ fallback: true }).then((resp) => {
|
|
51
|
-
auth = resp;
|
|
52
|
-
grabSheets(auth, project, directory, forceStr, options).then(() =>
|
|
53
|
-
resolveFinal()
|
|
54
|
-
);
|
|
55
|
-
});
|
|
56
|
-
});
|
|
48
|
+
.catch((err) => rejectFinal(err));
|
|
57
49
|
})
|
|
58
|
-
.catch(() =>
|
|
59
|
-
// Failure if we fall back but there's no token
|
|
60
|
-
auth = authObj.task();
|
|
61
|
-
grabSheets(auth, project, directory, forceStr, options).then(() =>
|
|
62
|
-
resolveFinal()
|
|
63
|
-
);
|
|
64
|
-
});
|
|
50
|
+
.catch((err) => rejectFinal(err));
|
|
65
51
|
});
|
|
66
52
|
};
|
|
67
53
|
|
|
@@ -74,10 +60,10 @@ let grabSheets = (auth, project, directory, forceStr, options = {}) => {
|
|
|
74
60
|
}
|
|
75
61
|
|
|
76
62
|
if (!sheetKeys || !sheetKeys.length) {
|
|
77
|
-
|
|
78
|
-
"You must specify a spreadsheet key in project.json or auth.json!"
|
|
63
|
+
rejectAll(
|
|
64
|
+
new Error("You must specify a spreadsheet key in project.json or auth.json!")
|
|
79
65
|
);
|
|
80
|
-
return
|
|
66
|
+
return;
|
|
81
67
|
}
|
|
82
68
|
|
|
83
69
|
let promiseStack = [];
|
|
@@ -123,9 +109,9 @@ let getSheet = async (
|
|
|
123
109
|
auth,
|
|
124
110
|
spreadsheetId,
|
|
125
111
|
})
|
|
126
|
-
.catch(() => {
|
|
112
|
+
.catch((err) => {
|
|
127
113
|
// This might fail if we don't have access
|
|
128
|
-
reject();
|
|
114
|
+
reject(err);
|
|
129
115
|
});
|
|
130
116
|
if (!output) {
|
|
131
117
|
return;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sfc-utils",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.211",
|
|
4
4
|
"author": "ewagstaff <evanjwagstaff@gmail.com>",
|
|
5
5
|
"dependencies": {
|
|
6
6
|
"archieml": "^0.4.2",
|
|
@@ -8,7 +8,6 @@
|
|
|
8
8
|
"googleapis": "59.0.0",
|
|
9
9
|
"html-entities": "1.3.1",
|
|
10
10
|
"htmlparser2": "4.1.0",
|
|
11
|
-
"opn": "^6.0.0",
|
|
12
11
|
"prop-types": "^15.8.1",
|
|
13
12
|
"react-helmet": "^6.1.0",
|
|
14
13
|
"react-transition-group": "^4.4.5",
|