aigma 0.1.1
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 +58 -0
- package/dist/commands/create-node.js +63 -0
- package/dist/commands/create-node.js.map +1 -0
- package/dist/commands/login.js +85 -0
- package/dist/commands/login.js.map +1 -0
- package/dist/index.js +42 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/config.js +8 -0
- package/dist/lib/config.js.map +1 -0
- package/dist/lib/output.js +29 -0
- package/dist/lib/output.js.map +1 -0
- package/dist/lib/session.js +64 -0
- package/dist/lib/session.js.map +1 -0
- package/package.json +47 -0
package/README.md
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# aigma
|
|
2
|
+
|
|
3
|
+
Generate Aigma canvas nodes from your terminal.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install -g aigma
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
# Sign in via your browser (Google or Apple)
|
|
15
|
+
aigma login
|
|
16
|
+
|
|
17
|
+
# Generate a node from a prompt
|
|
18
|
+
aigma create-node --prompt "Hero section for an AI photo editor"
|
|
19
|
+
|
|
20
|
+
# Save the generated HTML to a file
|
|
21
|
+
aigma create-node --prompt "Pricing section" --output pricing.html
|
|
22
|
+
|
|
23
|
+
# Get JSON on stdout for scripting
|
|
24
|
+
aigma create-node --prompt "Footer with links" --json
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Each `create-node` call:
|
|
28
|
+
|
|
29
|
+
1. Generates a self-contained HTML fragment with Gemini.
|
|
30
|
+
2. Publishes it to a public `https://aigma.co/p/{slug}` URL.
|
|
31
|
+
3. Drops a draft node onto your Aigma canvas — it appears within ~5s
|
|
32
|
+
if you have https://aigma.co/nodes open, or on next load.
|
|
33
|
+
|
|
34
|
+
You can run the same command repeatedly to iterate — every call creates
|
|
35
|
+
a new node so you can compare variations side-by-side on the canvas.
|
|
36
|
+
|
|
37
|
+
## Output rules
|
|
38
|
+
|
|
39
|
+
- Human-readable messages go to **stderr**.
|
|
40
|
+
- `--json` payload goes to **stdout** (one JSON object).
|
|
41
|
+
- Exit codes: `0` ok · `1` generic · `2` validation · `3` auth required.
|
|
42
|
+
|
|
43
|
+
## Config
|
|
44
|
+
|
|
45
|
+
By default the CLI talks to production Aigma. To point at a different
|
|
46
|
+
environment, set:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
export AIGMA_SUPABASE_URL=https://your-project.supabase.co
|
|
50
|
+
export AIGMA_SUPABASE_ANON_KEY=...
|
|
51
|
+
export AIGMA_WEB_BASE=https://your-app.example.com
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Credentials are stored at `~/.aigma/credentials.json` (mode 0600).
|
|
55
|
+
|
|
56
|
+
## License
|
|
57
|
+
|
|
58
|
+
MIT
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { promises as fs } from 'node:fs';
|
|
2
|
+
import { authenticatedClient } from '../lib/session.js';
|
|
3
|
+
import { FUNCTIONS_BASE, SUPABASE_ANON_KEY } from '../lib/config.js';
|
|
4
|
+
import { info, success, json, error, ExitCode } from '../lib/output.js';
|
|
5
|
+
export async function runCreateNode(opts) {
|
|
6
|
+
if (!opts.prompt || !opts.prompt.trim()) {
|
|
7
|
+
error('--prompt is required');
|
|
8
|
+
process.exit(ExitCode.Validation);
|
|
9
|
+
}
|
|
10
|
+
const auth = await authenticatedClient();
|
|
11
|
+
if (!auth) {
|
|
12
|
+
error('Not authenticated. Run `aigma login` first.');
|
|
13
|
+
process.exit(ExitCode.AuthRequired);
|
|
14
|
+
}
|
|
15
|
+
info('Generating node...');
|
|
16
|
+
let res;
|
|
17
|
+
try {
|
|
18
|
+
res = await fetch(`${FUNCTIONS_BASE}/cli-create-node`, {
|
|
19
|
+
method: 'POST',
|
|
20
|
+
headers: {
|
|
21
|
+
'Content-Type': 'application/json',
|
|
22
|
+
Authorization: `Bearer ${auth.accessToken}`,
|
|
23
|
+
apikey: SUPABASE_ANON_KEY,
|
|
24
|
+
},
|
|
25
|
+
body: JSON.stringify({ prompt: opts.prompt }),
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
catch (err) {
|
|
29
|
+
error(`Network error: ${err.message}`);
|
|
30
|
+
process.exit(ExitCode.Generic);
|
|
31
|
+
}
|
|
32
|
+
let payload;
|
|
33
|
+
try {
|
|
34
|
+
payload = (await res.json());
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
error(`Server returned non-JSON response (status ${res.status})`);
|
|
38
|
+
process.exit(ExitCode.Generic);
|
|
39
|
+
}
|
|
40
|
+
if (!res.ok || payload.error) {
|
|
41
|
+
error(payload.error || `Request failed (status ${res.status})`);
|
|
42
|
+
process.exit(res.status === 401 ? ExitCode.AuthRequired : ExitCode.Generic);
|
|
43
|
+
}
|
|
44
|
+
if (!payload.html) {
|
|
45
|
+
error('Server response missing html');
|
|
46
|
+
process.exit(ExitCode.Generic);
|
|
47
|
+
}
|
|
48
|
+
if (opts.output) {
|
|
49
|
+
await fs.writeFile(opts.output, payload.html, 'utf8');
|
|
50
|
+
success(`HTML written to ${opts.output}`);
|
|
51
|
+
}
|
|
52
|
+
if (payload.public_url) {
|
|
53
|
+
info(` Public: ${payload.public_url}`);
|
|
54
|
+
}
|
|
55
|
+
if (payload.canvas_url) {
|
|
56
|
+
info(` Canvas: ${payload.canvas_url}`);
|
|
57
|
+
}
|
|
58
|
+
success('Node created');
|
|
59
|
+
if (opts.json) {
|
|
60
|
+
json(payload);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=create-node.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-node.js","sourceRoot":"","sources":["../../src/commands/create-node.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { createServer } from 'node:http';
|
|
2
|
+
import { randomBytes } from 'node:crypto';
|
|
3
|
+
import open from 'open';
|
|
4
|
+
import { writeSession } from '../lib/session.js';
|
|
5
|
+
import { WEB_BASE } from '../lib/config.js';
|
|
6
|
+
import { info, success, json } from '../lib/output.js';
|
|
7
|
+
export async function runLogin(opts) {
|
|
8
|
+
const state = randomBytes(16).toString('hex');
|
|
9
|
+
const session = await new Promise((resolve, reject) => {
|
|
10
|
+
const server = createServer((req, res) => {
|
|
11
|
+
// CORS — accept any origin. The server is bound to 127.0.0.1 and
|
|
12
|
+
// protected by the per-request `state` token, so origin restriction
|
|
13
|
+
// adds no real security and breaks www↔apex redirects.
|
|
14
|
+
res.setHeader('Access-Control-Allow-Origin', '*');
|
|
15
|
+
res.setHeader('Access-Control-Allow-Methods', 'POST, OPTIONS');
|
|
16
|
+
res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
|
|
17
|
+
if (req.method === 'OPTIONS') {
|
|
18
|
+
res.writeHead(204).end();
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
if (req.method !== 'POST' || !req.url?.startsWith('/callback')) {
|
|
22
|
+
res.writeHead(404).end();
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
let body = '';
|
|
26
|
+
req.on('data', (chunk) => (body += chunk));
|
|
27
|
+
req.on('end', () => {
|
|
28
|
+
try {
|
|
29
|
+
const payload = JSON.parse(body);
|
|
30
|
+
if (payload.state !== state) {
|
|
31
|
+
res.writeHead(400, { 'Content-Type': 'application/json' });
|
|
32
|
+
res.end(JSON.stringify({ error: 'state mismatch' }));
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
if (!payload.access_token || !payload.refresh_token || !payload.user) {
|
|
36
|
+
res.writeHead(400, { 'Content-Type': 'application/json' });
|
|
37
|
+
res.end(JSON.stringify({ error: 'missing fields' }));
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
41
|
+
res.end(JSON.stringify({ ok: true }));
|
|
42
|
+
server.close();
|
|
43
|
+
resolve({
|
|
44
|
+
access_token: payload.access_token,
|
|
45
|
+
refresh_token: payload.refresh_token,
|
|
46
|
+
expires_at: payload.expires_at ?? 0,
|
|
47
|
+
user: { id: payload.user.id, email: payload.user.email ?? null },
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
catch (err) {
|
|
51
|
+
res.writeHead(400, { 'Content-Type': 'application/json' });
|
|
52
|
+
res.end(JSON.stringify({ error: 'invalid json' }));
|
|
53
|
+
reject(err);
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
server.on('error', reject);
|
|
58
|
+
// Bind to loopback only on a random free port.
|
|
59
|
+
server.listen(0, '127.0.0.1', () => {
|
|
60
|
+
const addr = server.address();
|
|
61
|
+
if (typeof addr !== 'object' || !addr) {
|
|
62
|
+
reject(new Error('failed to bind local server'));
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
const port = addr.port;
|
|
66
|
+
const url = `${WEB_BASE}/cli-auth?port=${port}&state=${state}`;
|
|
67
|
+
info(`Opening browser to sign in...`);
|
|
68
|
+
info(` ${url}`);
|
|
69
|
+
open(url).catch(() => {
|
|
70
|
+
info(`If your browser didn't open, visit the URL above.`);
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
// 5 minute timeout.
|
|
74
|
+
setTimeout(() => {
|
|
75
|
+
server.close();
|
|
76
|
+
reject(new Error('Login timed out — please try again.'));
|
|
77
|
+
}, 5 * 60_000);
|
|
78
|
+
});
|
|
79
|
+
await writeSession(session);
|
|
80
|
+
success(`Signed in as ${session.user.email ?? session.user.id}`);
|
|
81
|
+
if (opts.json) {
|
|
82
|
+
json({ ok: true, user: session.user });
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=login.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"login.js","sourceRoot":"","sources":["../../src/commands/login.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Command } from 'commander';
|
|
3
|
+
import { runLogin } from './commands/login.js';
|
|
4
|
+
import { runCreateNode } from './commands/create-node.js';
|
|
5
|
+
import { exitWith } from './lib/output.js';
|
|
6
|
+
const program = new Command();
|
|
7
|
+
program
|
|
8
|
+
.name('aigma')
|
|
9
|
+
.description('Aigma CLI — generate canvas nodes from your terminal')
|
|
10
|
+
.version('0.1.0');
|
|
11
|
+
program
|
|
12
|
+
.command('login')
|
|
13
|
+
.description('Sign in to Aigma via your browser')
|
|
14
|
+
.option('--json', 'output JSON on stdout')
|
|
15
|
+
.action(async (opts) => {
|
|
16
|
+
try {
|
|
17
|
+
await runLogin({ json: !!opts.json });
|
|
18
|
+
}
|
|
19
|
+
catch (err) {
|
|
20
|
+
exitWith(1, err.message);
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
program
|
|
24
|
+
.command('create-node')
|
|
25
|
+
.description('Generate an HTML node from a prompt')
|
|
26
|
+
.requiredOption('-p, --prompt <text>', 'prompt describing the node')
|
|
27
|
+
.option('-o, --output <file>', 'write generated HTML to a file')
|
|
28
|
+
.option('--json', 'output JSON on stdout')
|
|
29
|
+
.action(async (opts) => {
|
|
30
|
+
try {
|
|
31
|
+
await runCreateNode({
|
|
32
|
+
prompt: opts.prompt,
|
|
33
|
+
output: opts.output,
|
|
34
|
+
json: !!opts.json,
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
catch (err) {
|
|
38
|
+
exitWith(1, err.message);
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
program.parseAsync(process.argv).catch((err) => exitWith(1, err.message));
|
|
42
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAC/C,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC1D,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAE3C,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,OAAO,CAAC;KACb,WAAW,CAAC,sDAAsD,CAAC;KACnE,OAAO,CAAC,OAAO,CAAC,CAAC;AAEpB,OAAO;KACJ,OAAO,CAAC,OAAO,CAAC;KAChB,WAAW,CAAC,mCAAmC,CAAC;KAChD,MAAM,CAAC,QAAQ,EAAE,uBAAuB,CAAC;KACzC,MAAM,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE;IACrB,IAAI,CAAC;QACH,MAAM,QAAQ,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;IACxC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,QAAQ,CAAC,CAAC,EAAG,GAAa,CAAC,OAAO,CAAC,CAAC;IACtC,CAAC;AACH,CAAC,CAAC,CAAC;AAEL,OAAO;KACJ,OAAO,CAAC,aAAa,CAAC;KACtB,WAAW,CAAC,qCAAqC,CAAC;KAClD,cAAc,CAAC,qBAAqB,EAAE,4BAA4B,CAAC;KACnE,MAAM,CAAC,qBAAqB,EAAE,gCAAgC,CAAC;KAC/D,MAAM,CAAC,QAAQ,EAAE,uBAAuB,CAAC;KACzC,MAAM,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE;IACrB,IAAI,CAAC;QACH,MAAM,aAAa,CAAC;YAClB,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI;SAClB,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,QAAQ,CAAC,CAAC,EAAG,GAAa,CAAC,OAAO,CAAC,CAAC;IACtC,CAAC;AACH,CAAC,CAAC,CAAC;AAEL,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
// Production defaults — overridable via env for development.
|
|
2
|
+
export const SUPABASE_URL = process.env.AIGMA_SUPABASE_URL ?? 'https://ekqbwjcvvuktnsuwnwnt.supabase.co';
|
|
3
|
+
// Public anon key. Safe to embed in CLI; matches the value the web app uses.
|
|
4
|
+
export const SUPABASE_ANON_KEY = process.env.AIGMA_SUPABASE_ANON_KEY ??
|
|
5
|
+
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImVrcWJ3amN2dnVrdG5zdXdud250Iiwicm9sZSI6ImFub24iLCJpYXQiOjE3Njk4MDA5NDcsImV4cCI6MjA4NTM3Njk0N30.nQxS2LpgZ6BwkhnHpn0Lngmo6ZxRnkfo-aMmo6wWUVs';
|
|
6
|
+
export const WEB_BASE = process.env.AIGMA_WEB_BASE ?? 'https://aigma.co';
|
|
7
|
+
export const FUNCTIONS_BASE = `${SUPABASE_URL}/functions/v1`;
|
|
8
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"AAAA,6DAA6D;AAC7D,MAAM,CAAC,MAAM,YAAY,GACvB,OAAO,CAAC,GAAG,CAAC,kBAAkB,IAAI,0CAA0C,CAAC;AAE/E,6EAA6E;AAC7E,MAAM,CAAC,MAAM,iBAAiB,GAC5B,OAAO,CAAC,GAAG,CAAC,uBAAuB;IACnC,kNAAkN,CAAC;AAErN,MAAM,CAAC,MAAM,QAAQ,GACnB,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,kBAAkB,CAAC;AAEnD,MAAM,CAAC,MAAM,cAAc,GAAG,GAAG,YAAY,eAAe,CAAC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import pc from 'picocolors';
|
|
2
|
+
// Human-readable lines go to stderr so stdout stays clean for --json piping.
|
|
3
|
+
export function info(msg) {
|
|
4
|
+
process.stderr.write(msg + '\n');
|
|
5
|
+
}
|
|
6
|
+
export function success(msg) {
|
|
7
|
+
process.stderr.write(pc.green('✓ ') + msg + '\n');
|
|
8
|
+
}
|
|
9
|
+
export function warn(msg) {
|
|
10
|
+
process.stderr.write(pc.yellow('! ') + msg + '\n');
|
|
11
|
+
}
|
|
12
|
+
export function error(msg) {
|
|
13
|
+
process.stderr.write(pc.red('✗ ') + msg + '\n');
|
|
14
|
+
}
|
|
15
|
+
export function json(obj) {
|
|
16
|
+
process.stdout.write(JSON.stringify(obj) + '\n');
|
|
17
|
+
}
|
|
18
|
+
export function exitWith(code, msg) {
|
|
19
|
+
if (msg)
|
|
20
|
+
error(msg);
|
|
21
|
+
process.exit(code);
|
|
22
|
+
}
|
|
23
|
+
export const ExitCode = {
|
|
24
|
+
Ok: 0,
|
|
25
|
+
Generic: 1,
|
|
26
|
+
Validation: 2,
|
|
27
|
+
AuthRequired: 3,
|
|
28
|
+
};
|
|
29
|
+
//# sourceMappingURL=output.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"output.js","sourceRoot":"","sources":["../../src/lib/output.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,YAAY,CAAC;AAE5B,6EAA6E;AAC7E,MAAM,UAAU,IAAI,CAAC,GAAW;IAC9B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,GAAG,IAAI,CAAC,CAAC;AACnC,CAAC;AAED,MAAM,UAAU,OAAO,CAAC,GAAW;IACjC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,GAAG,GAAG,IAAI,CAAC,CAAC;AACpD,CAAC;AAED,MAAM,UAAU,IAAI,CAAC,GAAW;IAC9B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,GAAG,GAAG,IAAI,CAAC,CAAC;AACrD,CAAC;AAED,MAAM,UAAU,KAAK,CAAC,GAAW;IAC/B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,GAAG,GAAG,IAAI,CAAC,CAAC;AAClD,CAAC;AAED,MAAM,UAAU,IAAI,CAAC,GAAY;IAC/B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,CAAC;AACnD,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,IAAY,EAAE,GAAY;IACjD,IAAI,GAAG;QAAE,KAAK,CAAC,GAAG,CAAC,CAAC;IACpB,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACrB,CAAC;AAED,MAAM,CAAC,MAAM,QAAQ,GAAG;IACtB,EAAE,EAAE,CAAC;IACL,OAAO,EAAE,CAAC;IACV,UAAU,EAAE,CAAC;IACb,YAAY,EAAE,CAAC;CACP,CAAC"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { createClient } from '@supabase/supabase-js';
|
|
2
|
+
import { promises as fs } from 'node:fs';
|
|
3
|
+
import { homedir } from 'node:os';
|
|
4
|
+
import { join } from 'node:path';
|
|
5
|
+
import { SUPABASE_URL, SUPABASE_ANON_KEY } from './config.js';
|
|
6
|
+
const CONFIG_DIR = join(homedir(), '.aigma');
|
|
7
|
+
const CREDS_PATH = join(CONFIG_DIR, 'credentials.json');
|
|
8
|
+
export async function readSession() {
|
|
9
|
+
try {
|
|
10
|
+
const raw = await fs.readFile(CREDS_PATH, 'utf8');
|
|
11
|
+
return JSON.parse(raw);
|
|
12
|
+
}
|
|
13
|
+
catch (err) {
|
|
14
|
+
if (err.code === 'ENOENT')
|
|
15
|
+
return null;
|
|
16
|
+
throw err;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
export async function writeSession(session) {
|
|
20
|
+
await fs.mkdir(CONFIG_DIR, { recursive: true, mode: 0o700 });
|
|
21
|
+
await fs.writeFile(CREDS_PATH, JSON.stringify(session, null, 2), { mode: 0o600 });
|
|
22
|
+
}
|
|
23
|
+
export async function clearSession() {
|
|
24
|
+
try {
|
|
25
|
+
await fs.unlink(CREDS_PATH);
|
|
26
|
+
}
|
|
27
|
+
catch (err) {
|
|
28
|
+
if (err.code !== 'ENOENT')
|
|
29
|
+
throw err;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
// Build an authenticated Supabase client, refreshing the token if needed.
|
|
33
|
+
// Returns the client + the (possibly refreshed) access token to use as Bearer.
|
|
34
|
+
export async function authenticatedClient() {
|
|
35
|
+
const stored = await readSession();
|
|
36
|
+
if (!stored)
|
|
37
|
+
return null;
|
|
38
|
+
const client = createClient(SUPABASE_URL, SUPABASE_ANON_KEY, {
|
|
39
|
+
auth: { persistSession: false, autoRefreshToken: false },
|
|
40
|
+
});
|
|
41
|
+
const { data, error } = await client.auth.setSession({
|
|
42
|
+
access_token: stored.access_token,
|
|
43
|
+
refresh_token: stored.refresh_token,
|
|
44
|
+
});
|
|
45
|
+
if (error || !data.session) {
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
// If supabase-js refreshed the token, persist the new pair.
|
|
49
|
+
if (data.session.access_token !== stored.access_token ||
|
|
50
|
+
data.session.refresh_token !== stored.refresh_token) {
|
|
51
|
+
await writeSession({
|
|
52
|
+
access_token: data.session.access_token,
|
|
53
|
+
refresh_token: data.session.refresh_token,
|
|
54
|
+
expires_at: data.session.expires_at ?? 0,
|
|
55
|
+
user: { id: data.session.user.id, email: data.session.user.email ?? null },
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
return {
|
|
59
|
+
client,
|
|
60
|
+
accessToken: data.session.access_token,
|
|
61
|
+
userId: data.session.user.id,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=session.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session.js","sourceRoot":"","sources":["../../src/lib/session.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "aigma",
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "Aigma CLI — generate canvas nodes from your terminal",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"homepage": "https://aigma.co",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/pro-ect/nigma.git",
|
|
10
|
+
"directory": "apps/cli"
|
|
11
|
+
},
|
|
12
|
+
"keywords": [
|
|
13
|
+
"aigma",
|
|
14
|
+
"cli",
|
|
15
|
+
"ai",
|
|
16
|
+
"html",
|
|
17
|
+
"design",
|
|
18
|
+
"canvas"
|
|
19
|
+
],
|
|
20
|
+
"type": "module",
|
|
21
|
+
"bin": {
|
|
22
|
+
"aigma": "./dist/index.js"
|
|
23
|
+
},
|
|
24
|
+
"scripts": {
|
|
25
|
+
"build": "tsc && chmod +x dist/index.js",
|
|
26
|
+
"dev": "tsc --watch",
|
|
27
|
+
"start": "node dist/index.js",
|
|
28
|
+
"typecheck": "tsc --noEmit",
|
|
29
|
+
"prepublishOnly": "pnpm run build"
|
|
30
|
+
},
|
|
31
|
+
"dependencies": {
|
|
32
|
+
"@supabase/supabase-js": "^2.45.0",
|
|
33
|
+
"commander": "^12.1.0",
|
|
34
|
+
"open": "^10.1.0",
|
|
35
|
+
"picocolors": "^1.1.1"
|
|
36
|
+
},
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"@types/node": "^20.14.0",
|
|
39
|
+
"typescript": "^5.4.5"
|
|
40
|
+
},
|
|
41
|
+
"engines": {
|
|
42
|
+
"node": ">=18.17.0"
|
|
43
|
+
},
|
|
44
|
+
"files": [
|
|
45
|
+
"dist"
|
|
46
|
+
]
|
|
47
|
+
}
|