@quenty/nevermore-cli-helpers 1.8.1 → 1.10.0

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.
Files changed (53) hide show
  1. package/CHANGELOG.md +10 -47
  2. package/dist/auth/cookie/cookie-parser.d.ts +7 -0
  3. package/dist/auth/cookie/cookie-parser.d.ts.map +1 -0
  4. package/dist/auth/cookie/cookie-parser.js +18 -0
  5. package/dist/auth/cookie/cookie-parser.js.map +1 -0
  6. package/dist/auth/cookie/cookie-parser.test.d.ts +2 -0
  7. package/dist/auth/cookie/cookie-parser.test.d.ts.map +1 -0
  8. package/dist/auth/cookie/cookie-parser.test.js +32 -0
  9. package/dist/auth/cookie/cookie-parser.test.js.map +1 -0
  10. package/dist/auth/cookie/index.d.ts +41 -0
  11. package/dist/auth/cookie/index.d.ts.map +1 -0
  12. package/dist/auth/cookie/index.js +188 -0
  13. package/dist/auth/cookie/index.js.map +1 -0
  14. package/dist/auth/cookie/linux.d.ts +14 -0
  15. package/dist/auth/cookie/linux.d.ts.map +1 -0
  16. package/dist/auth/cookie/linux.js +147 -0
  17. package/dist/auth/cookie/linux.js.map +1 -0
  18. package/dist/auth/cookie/macos.d.ts +2 -0
  19. package/dist/auth/cookie/macos.d.ts.map +1 -0
  20. package/dist/auth/cookie/macos.js +66 -0
  21. package/dist/auth/cookie/macos.js.map +1 -0
  22. package/dist/auth/cookie/validate-cookie.test.d.ts +2 -0
  23. package/dist/auth/cookie/validate-cookie.test.d.ts.map +1 -0
  24. package/dist/auth/cookie/validate-cookie.test.js +27 -0
  25. package/dist/auth/cookie/validate-cookie.test.js.map +1 -0
  26. package/dist/auth/cookie/windows.d.ts +2 -0
  27. package/dist/auth/cookie/windows.d.ts.map +1 -0
  28. package/dist/auth/cookie/windows.js +76 -0
  29. package/dist/auth/cookie/windows.js.map +1 -0
  30. package/dist/auth/open-cloud/credential-store.d.ts +14 -0
  31. package/dist/auth/open-cloud/credential-store.d.ts.map +1 -0
  32. package/dist/auth/open-cloud/credential-store.js +108 -0
  33. package/dist/auth/open-cloud/credential-store.js.map +1 -0
  34. package/dist/utils.d.ts +5 -0
  35. package/dist/utils.d.ts.map +1 -1
  36. package/dist/utils.js +3 -0
  37. package/dist/utils.js.map +1 -1
  38. package/dist/version-checker.d.ts +2 -0
  39. package/dist/version-checker.d.ts.map +1 -1
  40. package/dist/version-checker.js +22 -20
  41. package/dist/version-checker.js.map +1 -1
  42. package/package.json +8 -4
  43. package/src/auth/cookie/cookie-parser.test.ts +38 -0
  44. package/src/auth/cookie/cookie-parser.ts +18 -0
  45. package/src/auth/cookie/index.ts +271 -0
  46. package/src/auth/cookie/linux.ts +175 -0
  47. package/src/auth/cookie/macos.ts +88 -0
  48. package/src/auth/cookie/validate-cookie.test.ts +39 -0
  49. package/src/auth/cookie/windows.ts +96 -0
  50. package/src/auth/open-cloud/credential-store.ts +149 -0
  51. package/src/utils.ts +25 -0
  52. package/src/version-checker.ts +28 -24
  53. package/tsconfig.tsbuildinfo +1 -1
@@ -0,0 +1,66 @@
1
+ import { execSync } from 'child_process';
2
+ import * as fs from 'fs';
3
+ import * as path from 'path';
4
+ import * as os from 'os';
5
+ import { OutputHelper } from '@quenty/cli-output-helpers';
6
+ /**
7
+ * Read from ~/Library/HTTPStorages/com.Roblox.RobloxStudio.binarycookies.
8
+ * This is a binary format — we shell out to Python to parse it since Node
9
+ * doesn't have a native binarycookies parser.
10
+ */
11
+ function readFromHTTPStorages() {
12
+ const cookiePath = path.join(os.homedir(), 'Library/HTTPStorages/com.Roblox.RobloxStudio.binarycookies');
13
+ if (!fs.existsSync(cookiePath)) {
14
+ return undefined;
15
+ }
16
+ const pyScript = `
17
+ import struct, sys
18
+ with open(sys.argv[1], 'rb') as f:
19
+ data = f.read()
20
+ idx = data.find(b'_|WARNING')
21
+ if idx >= 0:
22
+ end = data.find(b'\\x00', idx)
23
+ if end < 0: end = len(data)
24
+ print(data[idx:end].decode('utf-8', errors='ignore'))
25
+ `.trim();
26
+ try {
27
+ const result = execSync(`python3 -c ${JSON.stringify(pyScript)} ${JSON.stringify(cookiePath)}`, { encoding: 'utf-8', timeout: 5000, stdio: ['pipe', 'pipe', 'pipe'] }).trim();
28
+ if (result && result.startsWith('_|')) {
29
+ OutputHelper.verbose('Loaded cookie from macOS HTTPStorages.');
30
+ return result;
31
+ }
32
+ }
33
+ catch {
34
+ // Python parse failed
35
+ }
36
+ return undefined;
37
+ }
38
+ function readFromPlist() {
39
+ const plistPath = path.join(os.homedir(), 'Library/Preferences/com.roblox.RobloxStudioBrowser.plist');
40
+ if (!fs.existsSync(plistPath)) {
41
+ return undefined;
42
+ }
43
+ try {
44
+ const result = execSync(`defaults read com.roblox.RobloxStudioBrowser 2>/dev/null | grep ROBLOSECURITY`, { encoding: 'utf-8', timeout: 5000, stdio: ['pipe', 'pipe', 'pipe'] }).trim();
45
+ if (result) {
46
+ const cookieMatch = result.match(/COOK::<(.+?)>/);
47
+ if (cookieMatch) {
48
+ OutputHelper.verbose('Loaded cookie from macOS plist.');
49
+ return cookieMatch[1];
50
+ }
51
+ const valueMatch = result.match(/"([^"]*_\|[^"]*)"/);
52
+ if (valueMatch) {
53
+ OutputHelper.verbose('Loaded cookie from macOS plist.');
54
+ return valueMatch[1];
55
+ }
56
+ }
57
+ }
58
+ catch {
59
+ // plist read failed
60
+ }
61
+ return undefined;
62
+ }
63
+ export function readCookie() {
64
+ return readFromHTTPStorages() ?? readFromPlist();
65
+ }
66
+ //# sourceMappingURL=macos.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"macos.js","sourceRoot":"","sources":["../../../src/auth/cookie/macos.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAE1D;;;;GAIG;AACH,SAAS,oBAAoB;IAC3B,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAC1B,EAAE,CAAC,OAAO,EAAE,EACZ,4DAA4D,CAC7D,CAAC;IAEF,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC/B,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,MAAM,QAAQ,GAAG;;;;;;;;;CASlB,CAAC,IAAI,EAAE,CAAC;IAEP,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,QAAQ,CACrB,cAAc,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,EAAE,EACtE,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,CACtE,CAAC,IAAI,EAAE,CAAC;QAET,IAAI,MAAM,IAAI,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;YACtC,YAAY,CAAC,OAAO,CAAC,wCAAwC,CAAC,CAAC;YAC/D,OAAO,MAAM,CAAC;QAChB,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,sBAAsB;IACxB,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,SAAS,aAAa;IACpB,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CACzB,EAAE,CAAC,OAAO,EAAE,EACZ,0DAA0D,CAC3D,CAAC;IAEF,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QAC9B,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,QAAQ,CACrB,+EAA+E,EAC/E,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,CACtE,CAAC,IAAI,EAAE,CAAC;QAET,IAAI,MAAM,EAAE,CAAC;YACX,MAAM,WAAW,GAAG,MAAM,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC;YAClD,IAAI,WAAW,EAAE,CAAC;gBAChB,YAAY,CAAC,OAAO,CAAC,iCAAiC,CAAC,CAAC;gBACxD,OAAO,WAAW,CAAC,CAAC,CAAC,CAAC;YACxB,CAAC;YAED,MAAM,UAAU,GAAG,MAAM,CAAC,KAAK,CAAC,mBAAmB,CAAC,CAAC;YACrD,IAAI,UAAU,EAAE,CAAC;gBACf,YAAY,CAAC,OAAO,CAAC,iCAAiC,CAAC,CAAC;gBACxD,OAAO,UAAU,CAAC,CAAC,CAAC,CAAC;YACvB,CAAC;QACH,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,oBAAoB;IACtB,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,MAAM,UAAU,UAAU;IACxB,OAAO,oBAAoB,EAAE,IAAI,aAAa,EAAE,CAAC;AACnD,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=validate-cookie.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate-cookie.test.d.ts","sourceRoot":"","sources":["../../../src/auth/cookie/validate-cookie.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,27 @@
1
+ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
2
+ import { validateCookieAsync } from './index.js';
3
+ describe('validateCookieAsync', () => {
4
+ const originalFetch = globalThis.fetch;
5
+ beforeEach(() => {
6
+ vi.restoreAllMocks();
7
+ });
8
+ afterEach(() => {
9
+ globalThis.fetch = originalFetch;
10
+ });
11
+ it('returns valid when cookie is accepted (HTTP 200)', async () => {
12
+ globalThis.fetch = vi.fn().mockResolvedValue({ status: 200 });
13
+ const result = await validateCookieAsync('valid-cookie');
14
+ expect(result).toEqual({ valid: true });
15
+ });
16
+ it('returns invalid with status when cookie is rejected (HTTP 401)', async () => {
17
+ globalThis.fetch = vi.fn().mockResolvedValue({ status: 401 });
18
+ const result = await validateCookieAsync('expired-cookie');
19
+ expect(result).toEqual({ valid: false, reason: 'invalid', status: 401 });
20
+ });
21
+ it('returns network_error when fetch throws', async () => {
22
+ globalThis.fetch = vi.fn().mockRejectedValue(new Error('network error'));
23
+ const result = await validateCookieAsync('some-cookie');
24
+ expect(result).toEqual({ valid: false, reason: 'network_error' });
25
+ });
26
+ });
27
+ //# sourceMappingURL=validate-cookie.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate-cookie.test.js","sourceRoot":"","sources":["../../../src/auth/cookie/validate-cookie.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AAEzE,OAAO,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAEjD,QAAQ,CAAC,qBAAqB,EAAE,GAAG,EAAE;IACnC,MAAM,aAAa,GAAG,UAAU,CAAC,KAAK,CAAC;IAEvC,UAAU,CAAC,GAAG,EAAE;QACd,EAAE,CAAC,eAAe,EAAE,CAAC;IACvB,CAAC,CAAC,CAAC;IAEH,SAAS,CAAC,GAAG,EAAE;QACb,UAAU,CAAC,KAAK,GAAG,aAAa,CAAC;IACnC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kDAAkD,EAAE,KAAK,IAAI,EAAE;QAChE,UAAU,CAAC,KAAK,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC;QAE9D,MAAM,MAAM,GAAG,MAAM,mBAAmB,CAAC,cAAc,CAAC,CAAC;QAEzD,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IAC1C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gEAAgE,EAAE,KAAK,IAAI,EAAE;QAC9E,UAAU,CAAC,KAAK,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC;QAE9D,MAAM,MAAM,GAAG,MAAM,mBAAmB,CAAC,gBAAgB,CAAC,CAAC;QAE3D,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC;IAC3E,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,yCAAyC,EAAE,KAAK,IAAI,EAAE;QACvD,UAAU,CAAC,KAAK,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,IAAI,KAAK,CAAC,eAAe,CAAC,CAAC,CAAC;QAEzE,MAAM,MAAM,GAAG,MAAM,mBAAmB,CAAC,aAAa,CAAC,CAAC;QAExD,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,eAAe,EAAE,CAAC,CAAC;IACpE,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function readCookie(): string | undefined;
2
+ //# sourceMappingURL=windows.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"windows.d.ts","sourceRoot":"","sources":["../../../src/auth/cookie/windows.ts"],"names":[],"mappings":"AAqEA,wBAAgB,UAAU,IAAI,MAAM,GAAG,SAAS,CA0B/C"}
@@ -0,0 +1,76 @@
1
+ import { execSync } from 'child_process';
2
+ import { OutputHelper } from '@quenty/cli-output-helpers';
3
+ import { COOKIE_NAME, parseStudioCookieValue } from './cookie-parser.js';
4
+ /**
5
+ * Read a generic credential from Windows Credential Manager via CredRead.
6
+ * The blob is decoded as UTF-8 (matching Mantle's wincred.rs).
7
+ */
8
+ function winCredRead(target) {
9
+ const escapedTarget = target.replace(/'/g, "''");
10
+ const script = [
11
+ `Add-Type -TypeDefinition '`,
12
+ `using System; using System.Runtime.InteropServices; using System.Text;`,
13
+ `public class NevCred {`,
14
+ ` [DllImport("advapi32.dll",SetLastError=true,CharSet=CharSet.Unicode)]`,
15
+ ` public static extern bool CredRead(string t,int ty,int f,out IntPtr c);`,
16
+ ` [DllImport("advapi32.dll",SetLastError=true)]`,
17
+ ` public static extern bool CredFree(IntPtr c);`,
18
+ ` [StructLayout(LayoutKind.Sequential,CharSet=CharSet.Unicode)]`,
19
+ ` public struct CRED { public int F; public int T; public string TN; public string Co;`,
20
+ ` public System.Runtime.InteropServices.ComTypes.FILETIME LW;`,
21
+ ` public int CBS; public IntPtr CB; public int P; public int AC; public IntPtr At;`,
22
+ ` public string TA; public string UN; }`,
23
+ ` public static string Read(string t) {`,
24
+ ` IntPtr p; if(!CredRead(t,1,0,out p)) return null;`,
25
+ ` try { CRED c=(CRED)Marshal.PtrToStructure(p,typeof(CRED));`,
26
+ ` if(c.CBS<=0) return "";`,
27
+ ` byte[] b=new byte[c.CBS]; Marshal.Copy(c.CB,b,0,c.CBS);`,
28
+ ` return Encoding.UTF8.GetString(b);`,
29
+ ` } finally { CredFree(p); } } }`,
30
+ `'; [NevCred]::Read('${escapedTarget}')`,
31
+ ].join(' ');
32
+ try {
33
+ const result = execSync(`powershell -NoProfile -ExecutionPolicy Bypass -Command "${script.replace(/"/g, '\\"')}"`, { encoding: 'utf-8', timeout: 10000, stdio: ['pipe', 'pipe', 'pipe'] }).trim();
34
+ return result.length > 0 ? result : undefined;
35
+ }
36
+ catch {
37
+ return undefined;
38
+ }
39
+ }
40
+ function readFromRegistry() {
41
+ try {
42
+ const script = `(Get-ItemProperty -Path 'HKCU:\\Software\\Roblox\\RobloxStudioBrowser\\roblox.com' -Name '${COOKIE_NAME}' -ErrorAction SilentlyContinue).'${COOKIE_NAME}'`;
43
+ const result = execSync(`powershell -NoProfile -ExecutionPolicy Bypass -Command "${script}"`, { encoding: 'utf-8', timeout: 5000, stdio: ['pipe', 'pipe', 'pipe'] }).trim();
44
+ if (result && result.length > 10) {
45
+ const parsed = parseStudioCookieValue(result);
46
+ if (parsed) {
47
+ OutputHelper.verbose('Loaded cookie from Windows Registry.');
48
+ return parsed;
49
+ }
50
+ }
51
+ }
52
+ catch {
53
+ // Registry read failed
54
+ }
55
+ return undefined;
56
+ }
57
+ export function readCookie() {
58
+ // Modern Studio: user-specific credential
59
+ const userId = winCredRead('https://www.roblox.com:RobloxStudioAuthuserid');
60
+ if (userId) {
61
+ const cookie = winCredRead(`https://www.roblox.com:RobloxStudioAuth${COOKIE_NAME}${userId}`);
62
+ if (cookie) {
63
+ OutputHelper.verbose(`Loaded cookie from Windows Credentials (user ${userId}).`);
64
+ return cookie;
65
+ }
66
+ }
67
+ // Legacy credential (no user ID suffix)
68
+ const legacyCookie = winCredRead(`https://www.roblox.com:RobloxStudioAuth${COOKIE_NAME}`);
69
+ if (legacyCookie) {
70
+ OutputHelper.verbose('Loaded cookie from Windows Credentials (legacy).');
71
+ return legacyCookie;
72
+ }
73
+ // Oldest fallback: Windows Registry
74
+ return readFromRegistry();
75
+ }
76
+ //# sourceMappingURL=windows.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"windows.js","sourceRoot":"","sources":["../../../src/auth/cookie/windows.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ export interface CredentialArgs {
2
+ apiKey?: string;
3
+ yes?: boolean;
4
+ }
5
+ export declare function printApiKeySetupHelp(): void;
6
+ export declare function loadStoredApiKeyAsync(): Promise<string | undefined>;
7
+ export declare function saveApiKeyAsync(apiKey: string): Promise<void>;
8
+ export declare function clearApiKeyAsync(): Promise<void>;
9
+ export declare function getApiKeyAsync(args: CredentialArgs): Promise<string>;
10
+ export declare function validateApiKeyAsync(apiKey: string): Promise<{
11
+ valid: boolean;
12
+ reason?: string;
13
+ }>;
14
+ //# sourceMappingURL=credential-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"credential-store.d.ts","sourceRoot":"","sources":["../../../src/auth/open-cloud/credential-store.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,cAAc;IAC7B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,GAAG,CAAC,EAAE,OAAO,CAAC;CACf;AAKD,wBAAgB,oBAAoB,IAAI,IAAI,CAgB3C;AAMD,wBAAsB,qBAAqB,IAAI,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAQzE;AAED,wBAAsB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAMnE;AAED,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,IAAI,CAAC,CAMtD;AAED,wBAAsB,cAAc,CAAC,IAAI,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC,CA8B1E;AAED,wBAAsB,mBAAmB,CACvC,MAAM,EAAE,MAAM,GACb,OAAO,CAAC;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAuB9C"}
@@ -0,0 +1,108 @@
1
+ import * as fs from 'fs/promises';
2
+ import * as path from 'path';
3
+ import * as os from 'os';
4
+ import inquirer from 'inquirer';
5
+ import { OutputHelper } from '@quenty/cli-output-helpers';
6
+ const CREDENTIALS_DIR = path.join(os.homedir(), '.nevermore');
7
+ const CREDENTIALS_PATH = path.join(CREDENTIALS_DIR, 'credentials.json');
8
+ export function printApiKeySetupHelp() {
9
+ console.log('');
10
+ OutputHelper.info('Create an API key at https://create.roblox.com/dashboard/credentials');
11
+ console.log('');
12
+ console.log('Required permissions:');
13
+ console.log(' - universe-places:write (upload place files)');
14
+ console.log(' - universe.place.luau-execution-session:write (run scripts)');
15
+ console.log(' - universe.place.luau-execution-session:read (read results)');
16
+ console.log(' - legacy-asset:manage (download base places for integration builds)');
17
+ console.log('');
18
+ }
19
+ export async function loadStoredApiKeyAsync() {
20
+ try {
21
+ const content = await fs.readFile(CREDENTIALS_PATH, 'utf-8');
22
+ const credentials = JSON.parse(content);
23
+ return credentials.apiKey;
24
+ }
25
+ catch {
26
+ return undefined;
27
+ }
28
+ }
29
+ export async function saveApiKeyAsync(apiKey) {
30
+ await fs.mkdir(CREDENTIALS_DIR, { recursive: true, mode: 0o700 });
31
+ const credentials = { apiKey };
32
+ await fs.writeFile(CREDENTIALS_PATH, JSON.stringify(credentials, null, 2), {
33
+ mode: 0o600,
34
+ });
35
+ }
36
+ export async function clearApiKeyAsync() {
37
+ try {
38
+ await fs.unlink(CREDENTIALS_PATH);
39
+ }
40
+ catch {
41
+ // Already gone
42
+ }
43
+ }
44
+ export async function getApiKeyAsync(args) {
45
+ if (args.apiKey) {
46
+ return args.apiKey;
47
+ }
48
+ if (process.env.ROBLOX_OPEN_CLOUD_API_KEY) {
49
+ return process.env.ROBLOX_OPEN_CLOUD_API_KEY;
50
+ }
51
+ if (process.env.ROBLOX_UNIT_TEST_API_KEY) {
52
+ return process.env.ROBLOX_UNIT_TEST_API_KEY;
53
+ }
54
+ const stored = await loadStoredApiKeyAsync();
55
+ if (stored) {
56
+ return stored;
57
+ }
58
+ if (!args.yes) {
59
+ return await promptAndSaveApiKeyAsync();
60
+ }
61
+ throw new Error([
62
+ 'No API key found. Provide one of:',
63
+ ' - Run: nevermore login',
64
+ ' - Set: ROBLOX_OPEN_CLOUD_API_KEY environment variable',
65
+ ' - Pass: --api-key <key>',
66
+ ].join('\n'));
67
+ }
68
+ export async function validateApiKeyAsync(apiKey) {
69
+ try {
70
+ const response = await fetch('https://apis.roblox.com/cloud/v2/universes/0', {
71
+ method: 'GET',
72
+ headers: { 'X-API-Key': apiKey },
73
+ });
74
+ if (response.status === 401) {
75
+ return { valid: false, reason: 'Invalid API key (401 Unauthorized)' };
76
+ }
77
+ return { valid: true };
78
+ }
79
+ catch (err) {
80
+ return {
81
+ valid: false,
82
+ reason: `Could not reach Roblox API: ${err instanceof Error ? err.message : 'unknown'}`,
83
+ };
84
+ }
85
+ }
86
+ async function promptAndSaveApiKeyAsync() {
87
+ OutputHelper.warn('No API key found. Starting login...');
88
+ printApiKeySetupHelp();
89
+ const { apiKey } = await inquirer.prompt([
90
+ {
91
+ type: 'password',
92
+ name: 'apiKey',
93
+ message: 'Enter your Roblox Open Cloud API key:',
94
+ mask: '*',
95
+ validate: (input) => input.length > 0 || 'API key cannot be empty',
96
+ },
97
+ ]);
98
+ OutputHelper.info('Validating API key...');
99
+ const validation = await validateApiKeyAsync(apiKey);
100
+ if (!validation.valid) {
101
+ throw new Error(`API key validation failed: ${validation.reason}`);
102
+ }
103
+ await saveApiKeyAsync(apiKey);
104
+ OutputHelper.info('API key is valid. Saved to ~/.nevermore/credentials.json');
105
+ console.log('');
106
+ return apiKey;
107
+ }
108
+ //# sourceMappingURL=credential-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"credential-store.js","sourceRoot":"","sources":["../../../src/auth/open-cloud/credential-store.ts"],"names":[],"mappings":"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"}
package/dist/utils.d.ts CHANGED
@@ -1,2 +1,7 @@
1
1
  export { VersionChecker } from './version-checker.js';
2
+ export { getRobloxCookieAsync, createPlaceInUniverseAsync, tryRenamePlaceAsync, validateCookieAsync, } from './auth/cookie/index.js';
3
+ export type { RenamePlaceResult, CookieValidationResult, } from './auth/cookie/index.js';
4
+ export { COOKIE_NAME, parseStudioCookieValue, } from './auth/cookie/cookie-parser.js';
5
+ export { getApiKeyAsync, loadStoredApiKeyAsync, saveApiKeyAsync, clearApiKeyAsync, validateApiKeyAsync, printApiKeySetupHelp, } from './auth/open-cloud/credential-store.js';
6
+ export type { CredentialArgs } from './auth/open-cloud/credential-store.js';
2
7
  //# sourceMappingURL=utils.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC"}
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAEtD,OAAO,EACL,oBAAoB,EACpB,0BAA0B,EAC1B,mBAAmB,EACnB,mBAAmB,GACpB,MAAM,wBAAwB,CAAC;AAChC,YAAY,EACV,iBAAiB,EACjB,sBAAsB,GACvB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EACL,WAAW,EACX,sBAAsB,GACvB,MAAM,gCAAgC,CAAC;AAExC,OAAO,EACL,cAAc,EACd,qBAAqB,EACrB,eAAe,EACf,gBAAgB,EAChB,mBAAmB,EACnB,oBAAoB,GACrB,MAAM,uCAAuC,CAAC;AAC/C,YAAY,EAAE,cAAc,EAAE,MAAM,uCAAuC,CAAC"}
package/dist/utils.js CHANGED
@@ -1,2 +1,5 @@
1
1
  export { VersionChecker } from './version-checker.js';
2
+ export { getRobloxCookieAsync, createPlaceInUniverseAsync, tryRenamePlaceAsync, validateCookieAsync, } from './auth/cookie/index.js';
3
+ export { COOKIE_NAME, parseStudioCookieValue, } from './auth/cookie/cookie-parser.js';
4
+ export { getApiKeyAsync, loadStoredApiKeyAsync, saveApiKeyAsync, clearApiKeyAsync, validateApiKeyAsync, printApiKeySetupHelp, } from './auth/open-cloud/credential-store.js';
2
5
  //# sourceMappingURL=utils.js.map
package/dist/utils.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC"}
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAEtD,OAAO,EACL,oBAAoB,EACpB,0BAA0B,EAC1B,mBAAmB,EACnB,mBAAmB,GACpB,MAAM,wBAAwB,CAAC;AAKhC,OAAO,EACL,WAAW,EACX,sBAAsB,GACvB,MAAM,gCAAgC,CAAC;AAExC,OAAO,EACL,cAAc,EACd,qBAAqB,EACrB,eAAe,EACf,gBAAgB,EAChB,mBAAmB,EACnB,oBAAoB,GACrB,MAAM,uCAAuC,CAAC"}
@@ -14,6 +14,8 @@ interface VersionCheckerOptions {
14
14
  packageJsonPath?: string;
15
15
  updateCommand?: string;
16
16
  verbose?: boolean;
17
+ /** Suppress the visual banner (box). The result is still returned so callers can embed it in structured output. */
18
+ silent?: boolean;
17
19
  }
18
20
  export declare class VersionChecker {
19
21
  static checkForUpdatesAsync(options: VersionCheckerOptions): Promise<UpdateCheckResult | undefined>;
@@ -1 +1 @@
1
- {"version":3,"file":"version-checker.d.ts","sourceRoot":"","sources":["../src/version-checker.ts"],"names":[],"mappings":"AAAA;;GAEG;AAkBH,UAAU,iBAAiB;IACzB,eAAe,EAAE,OAAO,CAAC;IACzB,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,OAAO,CAAC;CACrB;AAED,UAAU,qBAAqB;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAOD,qBAAa,cAAc;WACL,oBAAoB,CACtC,OAAO,EAAE,qBAAqB,GAC7B,OAAO,CAAC,iBAAiB,GAAG,SAAS,CAAC;mBAapB,6BAA6B;IAmElD,OAAO,CAAC,MAAM,CAAC,eAAe;IAI9B;;OAEG;WACW,qBAAqB,CAAC,WAAW,EAAE,iBAAiB,GAAG,MAAM;IAO3E,OAAO,CAAC,MAAM,CAAC,2BAA2B;mBASrB,qBAAqB;mBAsCrB,sBAAsB;CAyE5C"}
1
+ {"version":3,"file":"version-checker.d.ts","sourceRoot":"","sources":["../src/version-checker.ts"],"names":[],"mappings":"AAAA;;GAEG;AAkBH,UAAU,iBAAiB;IACzB,eAAe,EAAE,OAAO,CAAC;IACzB,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,OAAO,CAAC;CACrB;AAED,UAAU,qBAAqB;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,mHAAmH;IACnH,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAOD,qBAAa,cAAc;WACL,oBAAoB,CACtC,OAAO,EAAE,qBAAqB,GAC7B,OAAO,CAAC,iBAAiB,GAAG,SAAS,CAAC;mBAapB,6BAA6B;IAqElD,OAAO,CAAC,MAAM,CAAC,eAAe;IAI9B;;OAEG;WACW,qBAAqB,CAAC,WAAW,EAAE,iBAAiB,GAAG,MAAM;IAO3E,OAAO,CAAC,MAAM,CAAC,2BAA2B;mBASrB,qBAAqB;mBAsCrB,sBAAsB;CAyE5C"}
@@ -40,26 +40,28 @@ export class VersionChecker {
40
40
  const currentyVersionDisplayName = VersionChecker._getLocalVersionDisplayName(versionData);
41
41
  OutputHelper.info(`Checked for updates for ${packageName}. Current version: ${currentyVersionDisplayName}, Latest version: ${result.latestVersion}, and update available: ${result.updateAvailable}`);
42
42
  }
43
- if (result.isLocalDev) {
44
- const name = VersionChecker._getDisplayName(options);
45
- const text = [
46
- `${name} is running in local development mode`,
47
- '',
48
- OutputHelper.formatHint(`Run '${updateCommand}' to switch to production copy`),
49
- '',
50
- 'This will result in less errors.',
51
- ].join('\n');
52
- OutputHelper.box(text, { centered: true });
53
- }
54
- else if (result.updateAvailable) {
55
- const name = VersionChecker._getDisplayName(options);
56
- const currentyVersionDisplayName = VersionChecker._getLocalVersionDisplayName(versionData);
57
- const text = [
58
- `${name} update available: ${currentyVersionDisplayName} → ${result.latestVersion}`,
59
- '',
60
- OutputHelper.formatHint(`Run '${updateCommand}' to update`),
61
- ].join('\n');
62
- OutputHelper.box(text, { centered: true });
43
+ if (!options.silent) {
44
+ if (result.isLocalDev) {
45
+ const name = VersionChecker._getDisplayName(options);
46
+ const text = [
47
+ `${name} is running in local development mode`,
48
+ '',
49
+ OutputHelper.formatHint(`Run '${updateCommand}' to switch to production copy`),
50
+ '',
51
+ 'This will result in less errors.',
52
+ ].join('\n');
53
+ OutputHelper.box(text, { centered: true });
54
+ }
55
+ else if (result.updateAvailable) {
56
+ const name = VersionChecker._getDisplayName(options);
57
+ const currentyVersionDisplayName = VersionChecker._getLocalVersionDisplayName(versionData);
58
+ const text = [
59
+ `${name} update available: ${currentyVersionDisplayName} → ${result.latestVersion}`,
60
+ '',
61
+ OutputHelper.formatHint(`Run '${updateCommand}' to update`),
62
+ ].join('\n');
63
+ OutputHelper.box(text, { centered: true });
64
+ }
63
65
  }
64
66
  return result;
65
67
  }
@@ -1 +1 @@
1
- {"version":3,"file":"version-checker.js","sourceRoot":"","sources":["../src/version-checker.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"version-checker.js","sourceRoot":"","sources":["../src/version-checker.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@quenty/nevermore-cli-helpers",
3
- "version": "1.8.1",
3
+ "version": "1.10.0",
4
4
  "description": "Helpers to generate Nevermore package and game templates",
5
5
  "type": "module",
6
6
  "keywords": [
@@ -22,7 +22,8 @@
22
22
  "Quenty"
23
23
  ],
24
24
  "dependencies": {
25
- "@quenty/cli-output-helpers": "1.10.1",
25
+ "@quenty/cli-output-helpers": "1.12.0",
26
+ "inquirer": "^13.2.0",
26
27
  "latest-version": "^9.0.0",
27
28
  "semver": "^7.6.0"
28
29
  },
@@ -31,12 +32,15 @@
31
32
  "@types/semver": "^7.5.0",
32
33
  "prettier": "2.7.1",
33
34
  "typescript": "^5.9.3",
34
- "typescript-memoize": "^1.1.1"
35
+ "typescript-memoize": "^1.1.1",
36
+ "vitest": "^3.0.0"
35
37
  },
36
38
  "scripts": {
37
39
  "build": "tsc --build",
38
40
  "build:watch": "tsc --build --watch",
39
41
  "build:clean": "tsc --build --clean",
42
+ "test": "vitest run",
43
+ "test:watch": "vitest",
40
44
  "preinstall": "npx only-allow pnpm"
41
45
  },
42
46
  "publishConfig": {
@@ -45,5 +49,5 @@
45
49
  "engines": {
46
50
  "node": ">=16"
47
51
  },
48
- "gitHead": "ab12ae11f52faf00116949383563934b2853b449"
52
+ "gitHead": "5cba15660c2856169fd0362e1eeeca4c260029c2"
49
53
  }
@@ -0,0 +1,38 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { COOKIE_NAME, parseStudioCookieValue } from './cookie-parser.js';
3
+
4
+ describe('COOKIE_NAME', () => {
5
+ it('equals .ROBLOSECURITY', () => {
6
+ expect(COOKIE_NAME).toBe('.ROBLOSECURITY');
7
+ });
8
+ });
9
+
10
+ describe('parseStudioCookieValue', () => {
11
+ it('parses COOK::<value> format with angle brackets', () => {
12
+ const result = parseStudioCookieValue('COOK::<abc123>');
13
+ expect(result).toBe('abc123');
14
+ });
15
+
16
+ it('parses value from comma-separated list', () => {
17
+ const result = parseStudioCookieValue('OTHER::stuff,COOK::<secret>');
18
+ expect(result).toBe('secret');
19
+ });
20
+
21
+ it('returns undefined for plain text', () => {
22
+ expect(parseStudioCookieValue('just a string')).toBeUndefined();
23
+ });
24
+
25
+ it('returns undefined for COOK:: without angle brackets', () => {
26
+ expect(parseStudioCookieValue('COOK::noBrackets')).toBeUndefined();
27
+ });
28
+
29
+ it('returns undefined for empty string', () => {
30
+ expect(parseStudioCookieValue('')).toBeUndefined();
31
+ });
32
+
33
+ it('handles a realistic cookie value', () => {
34
+ const cookie = '_|WARNING:-DO-NOT-SHARE|_abc123def456';
35
+ const result = parseStudioCookieValue(`COOK::<${cookie}>`);
36
+ expect(result).toBe(cookie);
37
+ });
38
+ });
@@ -0,0 +1,18 @@
1
+ export const COOKIE_NAME = '.ROBLOSECURITY';
2
+
3
+ /**
4
+ * Parse a Studio cookie value that may be in COOK::<cookie> format.
5
+ * Matches Mantle's parse_roblox_studio_cookie.
6
+ */
7
+ export function parseStudioCookieValue(value: string): string | undefined {
8
+ for (const item of value.split(',')) {
9
+ const parts = item.split('::');
10
+ if (parts.length === 2 && parts[0] === 'COOK') {
11
+ const cookie = parts[1];
12
+ if (cookie.startsWith('<') && cookie.endsWith('>')) {
13
+ return cookie.slice(1, -1);
14
+ }
15
+ }
16
+ }
17
+ return undefined;
18
+ }