pairit 0.1.1 → 0.1.3
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 +1 -0
- package/dist/index.js +75 -63
- package/package.json +41 -41
package/README.md
CHANGED
|
@@ -38,6 +38,7 @@ This makes `pairit` available globally from the `bin` field in package.json.
|
|
|
38
38
|
|
|
39
39
|
```bash
|
|
40
40
|
pairit login # Authenticate (required first)
|
|
41
|
+
# On a remote/headless server, open the printed URL locally and paste back the one-time code
|
|
41
42
|
|
|
42
43
|
pairit config lint path/to/config.yaml
|
|
43
44
|
pairit config compile path/to/config.yaml
|
package/dist/index.js
CHANGED
|
@@ -9955,73 +9955,74 @@ async function exchangeCodeForToken(code) {
|
|
|
9955
9955
|
async function login() {
|
|
9956
9956
|
console.log("Initiating login...");
|
|
9957
9957
|
const loginUrl = `${BASE_URL}/login`;
|
|
9958
|
-
|
|
9959
|
-
|
|
9960
|
-
|
|
9961
|
-
|
|
9962
|
-
|
|
9963
|
-
server
|
|
9964
|
-
|
|
9965
|
-
|
|
9966
|
-
|
|
9967
|
-
|
|
9968
|
-
|
|
9969
|
-
}
|
|
9970
|
-
});
|
|
9971
|
-
});
|
|
9972
|
-
const redirectUri = `http://127.0.0.1:${port}`;
|
|
9973
|
-
const targetUrl = `${loginUrl}?cli_redirect_uri=${encodeURIComponent(redirectUri)}`;
|
|
9974
|
-
console.log("Opening browser for authentication...");
|
|
9975
|
-
await open2(targetUrl);
|
|
9976
|
-
console.log(`Waiting for authentication at ${redirectUri}...`);
|
|
9977
|
-
const authCode = await new Promise((resolve, reject) => {
|
|
9978
|
-
const timeout = setTimeout(() => {
|
|
9979
|
-
server.close();
|
|
9980
|
-
reject(new Error("Login timed out"));
|
|
9981
|
-
}, 120000);
|
|
9982
|
-
server.on("request", (req, res) => {
|
|
9983
|
-
try {
|
|
9984
|
-
const url = new URL(req.url || "/", `http://${req.headers.host}`);
|
|
9985
|
-
const code = url.searchParams.get("code");
|
|
9986
|
-
if (code) {
|
|
9987
|
-
res.writeHead(200, { "Content-Type": "text/html" });
|
|
9988
|
-
res.end(`<!DOCTYPE html><html><head><title>Login Successful</title></head><body style="font-family:system-ui;display:flex;align-items:center;justify-content:center;height:100vh;margin:0"><div style="text-align:center"><h1>Authenticated!</h1><p>You can close this window and return to your CLI.</p></div><script>setTimeout(()=>window.close(),3000)</script></body></html>`);
|
|
9989
|
-
clearTimeout(timeout);
|
|
9990
|
-
server.close();
|
|
9991
|
-
resolve(code);
|
|
9958
|
+
const manualLoginUrl = `${loginUrl}?manual=1`;
|
|
9959
|
+
if (canAttemptBrowserLogin()) {
|
|
9960
|
+
try {
|
|
9961
|
+
const { createServer } = await import("node:http");
|
|
9962
|
+
const { default: open2 } = await Promise.resolve().then(() => (init_open(), exports_open));
|
|
9963
|
+
const server = createServer();
|
|
9964
|
+
const port = await new Promise((resolve, reject) => {
|
|
9965
|
+
server.listen(0, "127.0.0.1", () => {
|
|
9966
|
+
const address = server.address();
|
|
9967
|
+
if (address && typeof address === "object") {
|
|
9968
|
+
resolve(address.port);
|
|
9992
9969
|
} else {
|
|
9993
|
-
|
|
9994
|
-
res.end("Missing authorization code");
|
|
9970
|
+
reject(new Error("Could not determine port"));
|
|
9995
9971
|
}
|
|
9996
|
-
}
|
|
9997
|
-
res.writeHead(500);
|
|
9998
|
-
res.end("Error processing request");
|
|
9999
|
-
}
|
|
9972
|
+
});
|
|
10000
9973
|
});
|
|
10001
|
-
|
|
10002
|
-
|
|
10003
|
-
|
|
10004
|
-
|
|
10005
|
-
|
|
10006
|
-
|
|
10007
|
-
|
|
10008
|
-
|
|
9974
|
+
const redirectUri = `http://127.0.0.1:${port}`;
|
|
9975
|
+
const targetUrl = `${loginUrl}?cli_redirect_uri=${encodeURIComponent(redirectUri)}`;
|
|
9976
|
+
console.log("Opening browser for authentication...");
|
|
9977
|
+
await open2(targetUrl);
|
|
9978
|
+
console.log(`Waiting for authentication at ${redirectUri}...`);
|
|
9979
|
+
const authCode = await new Promise((resolve, reject) => {
|
|
9980
|
+
const timeout = setTimeout(() => {
|
|
9981
|
+
server.close();
|
|
9982
|
+
reject(new Error("Login timed out"));
|
|
9983
|
+
}, 120000);
|
|
9984
|
+
server.on("request", (req, res) => {
|
|
9985
|
+
try {
|
|
9986
|
+
const url = new URL(req.url || "/", `http://${req.headers.host}`);
|
|
9987
|
+
const code2 = url.searchParams.get("code");
|
|
9988
|
+
if (code2) {
|
|
9989
|
+
res.writeHead(200, { "Content-Type": "text/html" });
|
|
9990
|
+
res.end(`<!DOCTYPE html><html><head><title>Login Successful</title></head><body style="font-family:system-ui;display:flex;align-items:center;justify-content:center;height:100vh;margin:0"><div style="text-align:center"><h1>Authenticated!</h1><p>You can close this window and return to your CLI.</p></div><script>setTimeout(()=>window.close(),3000)</script></body></html>`);
|
|
9991
|
+
clearTimeout(timeout);
|
|
9992
|
+
server.close();
|
|
9993
|
+
resolve(code2);
|
|
9994
|
+
} else {
|
|
9995
|
+
res.writeHead(400);
|
|
9996
|
+
res.end("Missing authorization code");
|
|
9997
|
+
}
|
|
9998
|
+
} catch (_e) {
|
|
9999
|
+
res.writeHead(500);
|
|
10000
|
+
res.end("Error processing request");
|
|
10001
|
+
}
|
|
10002
|
+
});
|
|
10003
|
+
});
|
|
10004
|
+
console.log("Exchanging authorization code for token...");
|
|
10005
|
+
const token2 = await exchangeCodeForToken(authCode);
|
|
10006
|
+
await saveCredentials({ token: token2 });
|
|
10007
|
+
console.log("Successfully logged in!");
|
|
10008
|
+
return;
|
|
10009
|
+
} catch (error) {
|
|
10010
|
+
console.warn("Automated login failed, falling back to manual entry:", error instanceof Error ? error.message : String(error));
|
|
10011
|
+
}
|
|
10009
10012
|
}
|
|
10010
10013
|
console.log(`
|
|
10011
|
-
|
|
10014
|
+
Open this URL in a browser on any machine:
|
|
10015
|
+
${manualLoginUrl}
|
|
10012
10016
|
|
|
10013
|
-
After
|
|
10014
|
-
|
|
10017
|
+
After signing in, the page will show a one-time authorization code.
|
|
10018
|
+
Paste that code here to complete CLI login.
|
|
10015
10019
|
`);
|
|
10016
|
-
|
|
10017
|
-
|
|
10018
|
-
|
|
10019
|
-
} catch (_e) {}
|
|
10020
|
-
const token = await prompt("Enter session token (from browser): ");
|
|
10021
|
-
if (!token) {
|
|
10022
|
-
console.error("No token provided");
|
|
10020
|
+
const code = await prompt("Enter authorization code: ");
|
|
10021
|
+
if (!code) {
|
|
10022
|
+
console.error("No authorization code provided");
|
|
10023
10023
|
process.exit(1);
|
|
10024
10024
|
}
|
|
10025
|
+
const token = await exchangeCodeForToken(code);
|
|
10025
10026
|
await saveCredentials({ token });
|
|
10026
10027
|
console.log("Successfully logged in!");
|
|
10027
10028
|
}
|
|
@@ -10086,6 +10087,15 @@ async function prompt(question) {
|
|
|
10086
10087
|
});
|
|
10087
10088
|
});
|
|
10088
10089
|
}
|
|
10090
|
+
function canAttemptBrowserLogin() {
|
|
10091
|
+
if (!process.stdout.isTTY || !process.stdin.isTTY) {
|
|
10092
|
+
return false;
|
|
10093
|
+
}
|
|
10094
|
+
if (process.env.SSH_CONNECTION || process.env.SSH_CLIENT || process.env.SSH_TTY) {
|
|
10095
|
+
return false;
|
|
10096
|
+
}
|
|
10097
|
+
return process.platform === "darwin" || process.platform === "win32" || Boolean(process.env.DISPLAY || process.env.WAYLAND_DISPLAY);
|
|
10098
|
+
}
|
|
10089
10099
|
async function loadKeytar() {
|
|
10090
10100
|
try {
|
|
10091
10101
|
const runtimeImport = new Function("s", "return import(s)");
|
|
@@ -10336,6 +10346,7 @@ async function compileConfig(configPath) {
|
|
|
10336
10346
|
async function buildUploadPayload(configPath, options) {
|
|
10337
10347
|
const sourceConfig = await loadConfig(configPath);
|
|
10338
10348
|
const allowRetake = sourceConfig.allowRetake === true;
|
|
10349
|
+
const requireAuth = sourceConfig.requireAuth;
|
|
10339
10350
|
const compiledPath = await compileConfig(configPath);
|
|
10340
10351
|
const compiledContent = await readFile2(compiledPath, "utf8");
|
|
10341
10352
|
const hashBuffer = createHash("sha256").update(compiledContent).digest();
|
|
@@ -10352,7 +10363,8 @@ async function buildUploadPayload(configPath, options) {
|
|
|
10352
10363
|
checksum,
|
|
10353
10364
|
metadata: metadata ?? null,
|
|
10354
10365
|
config: parsed,
|
|
10355
|
-
allowRetake
|
|
10366
|
+
allowRetake,
|
|
10367
|
+
...requireAuth !== undefined && { requireAuth }
|
|
10356
10368
|
},
|
|
10357
10369
|
checksum
|
|
10358
10370
|
};
|
|
@@ -10558,11 +10570,11 @@ async function exportData(configId, options) {
|
|
|
10558
10570
|
Files written to: ${outDir}`);
|
|
10559
10571
|
}
|
|
10560
10572
|
function flattenSession(session) {
|
|
10561
|
-
const {
|
|
10573
|
+
const { session_state, prolific, ...rest } = session;
|
|
10562
10574
|
const flattened = { ...rest };
|
|
10563
|
-
if (
|
|
10564
|
-
for (const [key, value] of Object.entries(
|
|
10565
|
-
flattened[`
|
|
10575
|
+
if (session_state && typeof session_state === "object") {
|
|
10576
|
+
for (const [key, value] of Object.entries(session_state)) {
|
|
10577
|
+
flattened[`session_state.${key}`] = serializeValue(value);
|
|
10566
10578
|
}
|
|
10567
10579
|
}
|
|
10568
10580
|
if (prolific) {
|
package/package.json
CHANGED
|
@@ -1,43 +1,43 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
2
|
+
"name": "pairit",
|
|
3
|
+
"version": "0.1.3",
|
|
4
|
+
"description": "CLI for the Pairit behavioral science experiment platform",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"pairit": "dist/index.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"dist"
|
|
11
|
+
],
|
|
12
|
+
"scripts": {
|
|
13
|
+
"build": "bun build src/index.ts --outdir dist --target node",
|
|
14
|
+
"lint": "tsc --noEmit",
|
|
15
|
+
"prepublishOnly": "bun run build"
|
|
16
|
+
},
|
|
17
|
+
"keywords": [
|
|
18
|
+
"experiment",
|
|
19
|
+
"behavioral-science",
|
|
20
|
+
"research",
|
|
21
|
+
"cli"
|
|
22
|
+
],
|
|
23
|
+
"repository": {
|
|
24
|
+
"type": "git",
|
|
25
|
+
"url": "https://github.com/pairium/pairit.git",
|
|
26
|
+
"directory": "apps/manager/cli"
|
|
27
|
+
},
|
|
28
|
+
"homepage": "https://pairium.github.io/pairit/",
|
|
29
|
+
"license": "MIT",
|
|
30
|
+
"optionalDependencies": {
|
|
31
|
+
"keytar": "^7.9.0"
|
|
32
|
+
},
|
|
33
|
+
"devDependencies": {
|
|
34
|
+
"@types/bun": "^1.1.13",
|
|
35
|
+
"@types/open": "^6.2.1",
|
|
36
|
+
"better-auth": "^1.4.7",
|
|
37
|
+
"commander": "^12.1.0",
|
|
38
|
+
"dotenv": "^17.2.3",
|
|
39
|
+
"open": "^11.0.0",
|
|
40
|
+
"typescript": "^5.9.3",
|
|
41
|
+
"yaml": "^2.6.0"
|
|
42
|
+
}
|
|
43
43
|
}
|