@anby/cli 0.1.1 → 0.8.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.
@@ -0,0 +1,23 @@
1
+ /**
2
+ * `anby app codegen [--watch]` — PLAN-app-bootstrap-phase2 PR5.
3
+ *
4
+ * Reads `anby-app.manifest.json` and writes `.anby/types.d.ts` with
5
+ * TypeScript declaration merging that extends `@anby/platform-sdk`'s
6
+ * `AppProvidedEvents` and `AppRequiredEvents` interfaces. After this
7
+ * runs, calls to `publishEvent({ type: 'org.node.created', ... })` get
8
+ * compile-time autocomplete and typo-detection on the event name.
9
+ *
10
+ * For Vite users, prefer the `@anby/platform-sdk/vite` plugin which runs
11
+ * the same logic automatically as part of the dev server. This CLI
12
+ * exists for non-Vite runtimes (NestJS, plain Node, ESBuild, etc).
13
+ *
14
+ * `--watch` re-runs whenever the manifest file changes. Useful as a
15
+ * background process during dev: `anby app codegen --watch &`.
16
+ */
17
+ interface CodegenOptions {
18
+ manifest: string;
19
+ out: string;
20
+ watch?: boolean;
21
+ }
22
+ export declare function codegenCommand(options: CodegenOptions): Promise<void>;
23
+ export {};
@@ -0,0 +1,77 @@
1
+ import { readFileSync, writeFileSync, mkdirSync, watch, existsSync } from 'node:fs';
2
+ import { dirname, resolve, isAbsolute } from 'node:path';
3
+ import kleur from 'kleur';
4
+ function renderTypes(provides, requires) {
5
+ const sections = [];
6
+ sections.push('// Generated by @anby/cli — DO NOT EDIT.');
7
+ sections.push('// Re-runs whenever anby-app.manifest.json changes.');
8
+ sections.push('');
9
+ sections.push("declare module '@anby/platform-sdk' {");
10
+ if (provides.length > 0) {
11
+ sections.push(' interface AppProvidedEvents {');
12
+ for (const name of provides) {
13
+ sections.push(` ${JSON.stringify(name)}: Record<string, unknown>;`);
14
+ }
15
+ sections.push(' }');
16
+ }
17
+ else {
18
+ sections.push(' interface AppProvidedEvents {}');
19
+ }
20
+ if (requires.length > 0) {
21
+ sections.push(' interface AppRequiredEvents {');
22
+ for (const name of requires) {
23
+ sections.push(` ${JSON.stringify(name)}: Record<string, unknown>;`);
24
+ }
25
+ sections.push(' }');
26
+ }
27
+ else {
28
+ sections.push(' interface AppRequiredEvents {}');
29
+ }
30
+ sections.push('}');
31
+ sections.push('');
32
+ sections.push('export {};');
33
+ sections.push('');
34
+ return sections.join('\n');
35
+ }
36
+ function generate(manifestAbs, outAbs) {
37
+ if (!existsSync(manifestAbs)) {
38
+ console.error(kleur.red(`✖ Manifest not found at ${manifestAbs}`));
39
+ process.exit(1);
40
+ }
41
+ const raw = readFileSync(manifestAbs, 'utf-8');
42
+ const parsed = JSON.parse(raw);
43
+ const provides = Array.isArray(parsed.provides?.events) ? parsed.provides.events : [];
44
+ const requires = Array.isArray(parsed.requires?.events) ? parsed.requires.events : [];
45
+ const content = renderTypes(provides, requires);
46
+ mkdirSync(dirname(outAbs), { recursive: true });
47
+ writeFileSync(outAbs, content);
48
+ console.log(kleur.green(`✔ Wrote ${outAbs} (${provides.length} provided, ${requires.length} required)`));
49
+ }
50
+ export async function codegenCommand(options) {
51
+ const manifestAbs = isAbsolute(options.manifest)
52
+ ? options.manifest
53
+ : resolve(process.cwd(), options.manifest);
54
+ const outAbs = isAbsolute(options.out)
55
+ ? options.out
56
+ : resolve(process.cwd(), options.out);
57
+ generate(manifestAbs, outAbs);
58
+ if (options.watch) {
59
+ console.log(kleur.dim(`Watching ${manifestAbs} for changes... (Ctrl+C to exit)`));
60
+ let debounce = null;
61
+ watch(manifestAbs, () => {
62
+ if (debounce)
63
+ clearTimeout(debounce);
64
+ debounce = setTimeout(() => {
65
+ try {
66
+ generate(manifestAbs, outAbs);
67
+ }
68
+ catch (err) {
69
+ console.error(kleur.red(`✖ Codegen failed: ${err.message}`));
70
+ }
71
+ }, 100);
72
+ });
73
+ // Keep process alive
74
+ await new Promise(() => { });
75
+ }
76
+ }
77
+ //# sourceMappingURL=codegen.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codegen.js","sourceRoot":"","sources":["../../src/commands/codegen.ts"],"names":[],"mappings":"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"}
@@ -3,5 +3,9 @@ import type { Command } from 'commander';
3
3
  * All app-lifecycle commands live under `anby app <verb>` so we can add
4
4
  * other command namespaces later (`anby tenant`, `anby events`, etc.)
5
5
  * without reshuffling.
6
+ *
7
+ * `init` is also exposed as a top-level `anby init` alias because that's
8
+ * the command publishers reach for first and the namespace prefix would
9
+ * be a needless papercut on the very first interaction with the CLI.
6
10
  */
7
11
  export declare function registerAppCommands(program: Command): void;
@@ -3,19 +3,40 @@ import { validateCommand } from './validate.js';
3
3
  import { publishCommand } from './publish.js';
4
4
  import { installCommand } from './install.js';
5
5
  import { listCommand } from './list.js';
6
+ import { codegenCommand } from './codegen.js';
7
+ import { loginCommand } from './login.js';
8
+ import { logoutCommand } from './logout.js';
6
9
  /**
7
10
  * All app-lifecycle commands live under `anby app <verb>` so we can add
8
11
  * other command namespaces later (`anby tenant`, `anby events`, etc.)
9
12
  * without reshuffling.
13
+ *
14
+ * `init` is also exposed as a top-level `anby init` alias because that's
15
+ * the command publishers reach for first and the namespace prefix would
16
+ * be a needless papercut on the very first interaction with the CLI.
10
17
  */
11
18
  export function registerAppCommands(program) {
19
+ // ── Top-level auth commands ──────────────────────────────────────────
20
+ program
21
+ .command('login')
22
+ .description('Authenticate with the Anby platform via Google OAuth')
23
+ .option('--auth-url <url>', '[dev] Override auth service URL')
24
+ .action(loginCommand);
25
+ program
26
+ .command('logout')
27
+ .description('Remove stored CLI credentials')
28
+ .action(logoutCommand);
12
29
  const app = program.command('app').description('Manage Anby apps');
30
+ // Top-level alias: `anby init` → same as `anby app init`.
31
+ program
32
+ .command('init')
33
+ .description('Scaffold and register an Anby app (interactive)')
34
+ .option('--registry-url <url>', '[dev] Override registry URL')
35
+ .action(initCommand);
13
36
  app
14
37
  .command('init')
15
- .description('Scaffold a new anby-app.manifest.json in the current directory')
16
- .option('--id <id>', 'Reverse-domain app id, e.g. com.bravebits.hello')
17
- .option('--name <name>', 'Human-readable app name')
18
- .option('--port <port>', 'Runtime port', '3099')
38
+ .description('Scaffold and register an Anby app (interactive)')
39
+ .option('--registry-url <url>', '[dev] Override registry URL')
19
40
  .action(initCommand);
20
41
  app
21
42
  .command('validate')
@@ -30,6 +51,8 @@ export function registerAppCommands(program) {
30
51
  .option('--public-url <url>', 'Public URL where this service is reachable')
31
52
  .option('--changelog <text>', 'Optional changelog note attached to this version')
32
53
  .option('--featured', 'Flag the app as featured in the setup wizard')
54
+ .option('--save-to <path>', 'Write the assembled ANBY_APP_TOKEN to this file (e.g. .env.local)')
55
+ .option('--platform-url <url>', 'Override the platform base URL embedded in the token (defaults to registry URL with /registry stripped)')
33
56
  .action(publishCommand);
34
57
  app
35
58
  .command('install')
@@ -44,5 +67,12 @@ export function registerAppCommands(program) {
44
67
  .option('--tenant <tenantId>', 'Show installed apps for this tenant')
45
68
  .option('--registry <url>', 'Registry base URL', process.env.REGISTRY_URL || 'http://localhost:3003')
46
69
  .action(listCommand);
70
+ app
71
+ .command('codegen')
72
+ .description('Generate TypeScript types from anby-app.manifest.json (event names, etc)')
73
+ .option('--manifest <path>', 'Path to manifest file', './anby-app.manifest.json')
74
+ .option('--out <path>', 'Output path for generated types', './.anby/types.d.ts')
75
+ .option('--watch', 'Watch the manifest and regenerate on change')
76
+ .action(codegenCommand);
47
77
  }
48
78
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/commands/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAExC;;;;GAIG;AACH,MAAM,UAAU,mBAAmB,CAAC,OAAgB;IAClD,MAAM,GAAG,GAAG,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,WAAW,CAAC,kBAAkB,CAAC,CAAC;IAEnE,GAAG;SACA,OAAO,CAAC,MAAM,CAAC;SACf,WAAW,CAAC,gEAAgE,CAAC;SAC7E,MAAM,CAAC,WAAW,EAAE,iDAAiD,CAAC;SACtE,MAAM,CAAC,eAAe,EAAE,yBAAyB,CAAC;SAClD,MAAM,CAAC,eAAe,EAAE,cAAc,EAAE,MAAM,CAAC;SAC/C,MAAM,CAAC,WAAW,CAAC,CAAC;IAEvB,GAAG;SACA,OAAO,CAAC,UAAU,CAAC;SACnB,WAAW,CAAC,mEAAmE,CAAC;SAChF,MAAM,CAAC,mBAAmB,EAAE,uBAAuB,EAAE,0BAA0B,CAAC;SAChF,MAAM,CAAC,eAAe,CAAC,CAAC;IAE3B,GAAG;SACA,OAAO,CAAC,SAAS,CAAC;SAClB,WAAW,CAAC,sDAAsD,CAAC;SACnE,MAAM,CAAC,mBAAmB,EAAE,uBAAuB,EAAE,0BAA0B,CAAC;SAChF,MAAM,CAAC,kBAAkB,EAAE,mBAAmB,EAAE,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,uBAAuB,CAAC;SACpG,MAAM,CAAC,oBAAoB,EAAE,4CAA4C,CAAC;SAC1E,MAAM,CAAC,oBAAoB,EAAE,kDAAkD,CAAC;SAChF,MAAM,CAAC,YAAY,EAAE,8CAA8C,CAAC;SACpE,MAAM,CAAC,cAAc,CAAC,CAAC;IAE1B,GAAG;SACA,OAAO,CAAC,SAAS,CAAC;SAClB,WAAW,CAAC,6BAA6B,CAAC;SAC1C,cAAc,CAAC,qBAAqB,EAAE,WAAW,CAAC;SAClD,cAAc,CAAC,eAAe,EAAE,mBAAmB,CAAC;SACpD,MAAM,CAAC,kBAAkB,EAAE,mBAAmB,EAAE,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,uBAAuB,CAAC;SACpG,MAAM,CAAC,cAAc,CAAC,CAAC;IAE1B,GAAG;SACA,OAAO,CAAC,MAAM,CAAC;SACf,WAAW,CAAC,6DAA6D,CAAC;SAC1E,MAAM,CAAC,qBAAqB,EAAE,qCAAqC,CAAC;SACpE,MAAM,CAAC,kBAAkB,EAAE,mBAAmB,EAAE,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,uBAAuB,CAAC;SACpG,MAAM,CAAC,WAAW,CAAC,CAAC;AACzB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/commands/index.ts"],"names":[],"mappings":"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"}
@@ -1,12 +1,13 @@
1
1
  interface InitOptions {
2
- id?: string;
3
- name?: string;
4
- port?: string;
2
+ /** Hidden override for platform devs */
3
+ registryUrl?: string;
5
4
  }
6
5
  /**
7
- * Writes an `anby-app.manifest.json` skeleton that passes the AJV
8
- * schema out of the box. Refuses to overwrite an existing file so a
9
- * developer can't accidentally clobber their real manifest.
6
+ * `anby init` interactive scaffold + register.
7
+ *
8
+ * Prompts for app name and port, auto-generates a reverse-domain ID
9
+ * from the logged-in user's email domain, scaffolds all platform
10
+ * integration code, and registers with the registry.
10
11
  */
11
12
  export declare function initCommand(options: InitOptions): Promise<void>;
12
13
  export {};
@@ -1,41 +1,117 @@
1
- import { writeFile, access } from 'node:fs/promises';
1
+ import { writeFile, readFile, access, mkdir } from 'node:fs/promises';
2
2
  import { resolve } from 'node:path';
3
+ import { createInterface } from 'node:readline/promises';
3
4
  import kleur from 'kleur';
5
+ import { getStoredAuth, getEmailDomain } from '../lib/auth-store.js';
6
+ import { assembleToken } from '../lib/token.js';
7
+ const DEFAULT_REGISTRY_URL = 'https://registry.anby.ai';
4
8
  /**
5
- * Writes an `anby-app.manifest.json` skeleton that passes the AJV
6
- * schema out of the box. Refuses to overwrite an existing file so a
7
- * developer can't accidentally clobber their real manifest.
9
+ * `anby init` interactive scaffold + register.
10
+ *
11
+ * Prompts for app name and port, auto-generates a reverse-domain ID
12
+ * from the logged-in user's email domain, scaffolds all platform
13
+ * integration code, and registers with the registry.
8
14
  */
9
15
  export async function initCommand(options) {
16
+ const rl = createInterface({ input: process.stdin, output: process.stdout });
17
+ try {
18
+ // ── Collect inputs interactively ────────────────────────────────
19
+ const name = (await rl.question(kleur.bold('App name: '))).trim();
20
+ if (!name) {
21
+ console.log(kleur.red('✖ App name is required'));
22
+ return;
23
+ }
24
+ const portInput = (await rl.question(kleur.bold(`Port (default 3099): `))).trim();
25
+ const port = portInput ? Number.parseInt(portInput, 10) : 3099;
26
+ if (Number.isNaN(port)) {
27
+ console.log(kleur.red('✖ Invalid port'));
28
+ return;
29
+ }
30
+ // ── Auto-generate app ID ────────────────────────────────────────
31
+ const auth = await getStoredAuth();
32
+ const emailDomain = auth ? getEmailDomain(auth.email) : 'example.com';
33
+ // "bravebits.vn" → "vn.bravebits"
34
+ const reverseDomain = emailDomain.split('.').reverse().join('.');
35
+ // "Organization Chart" → "organization-chart"
36
+ const slug = name
37
+ .toLowerCase()
38
+ .replace(/[^a-z0-9]+/g, '-')
39
+ .replace(/^-|-$/g, '');
40
+ let id = `${reverseDomain}.${slug}`;
41
+ // Check if ID already exists in registry, append suffix if so
42
+ const registryBase = (options.registryUrl ||
43
+ process.env.ANBY_REGISTRY_URL ||
44
+ DEFAULT_REGISTRY_URL).replace(/\/+$/, '');
45
+ const existingId = await checkAppExists(registryBase, id);
46
+ if (existingId) {
47
+ // Append a short random suffix
48
+ const suffix = Math.random().toString(36).slice(2, 6);
49
+ id = `${reverseDomain}.${slug}-${suffix}`;
50
+ console.log(kleur.dim(` App ID "${reverseDomain}.${slug}" already taken → using ${id}`));
51
+ }
52
+ console.log(kleur.dim(` App ID: ${id}`));
53
+ console.log('');
54
+ // ── Scaffold ────────────────────────────────────────────────────
55
+ await writeManifest({ id, name, port });
56
+ await patchViteConfig();
57
+ await patchGitignore();
58
+ await scaffoldAuthServer();
59
+ await patchEntryServer(port);
60
+ await registerAndWriteToken({ id, name, port, registryBase, auth });
61
+ console.log('');
62
+ console.log(kleur.green('✔ Anby app bootstrap complete'));
63
+ console.log('');
64
+ console.log(kleur.bold('Next steps:'));
65
+ console.log(kleur.dim(` 1. Edit ${kleur.cyan('anby-app.manifest.json')} to declare provides/requires`));
66
+ console.log(kleur.dim(` (entities your app shares with or consumes from other apps)`));
67
+ console.log(kleur.dim(` 2. ${kleur.cyan('npm run dev')} — app auto-publishes manifest to registry on boot`));
68
+ console.log(kleur.dim(` 3. Install via Marketplace UI at ${kleur.cyan(`http://localhost:${port}`)}`));
69
+ }
70
+ finally {
71
+ rl.close();
72
+ }
73
+ }
74
+ // ── Helpers ─────────────────────────────────────────────────────────────
75
+ async function checkAppExists(registryBase, appId) {
76
+ try {
77
+ const res = await fetch(`${registryBase}/registry/apps/${appId}/manifest`, {
78
+ signal: AbortSignal.timeout(3000),
79
+ });
80
+ return res.ok;
81
+ }
82
+ catch {
83
+ // Registry unreachable — assume not taken
84
+ return false;
85
+ }
86
+ }
87
+ // ── Step 1: Manifest ──────────────────────────────────────────────────
88
+ async function writeManifest(opts) {
10
89
  const target = resolve('anby-app.manifest.json');
11
90
  try {
12
91
  await access(target);
13
- console.error(kleur.red(`✖ ${target} already exists — refusing to overwrite`));
14
- process.exit(1);
92
+ console.log(kleur.dim(`• ${target} already exists — leaving it alone`));
93
+ return;
15
94
  }
16
95
  catch {
17
96
  // ok — file doesn't exist
18
97
  }
19
- const id = options.id ?? 'com.example.my-app';
20
- const name = options.name ?? 'My App';
21
- const port = Number.parseInt(options.port ?? '3099', 10);
22
98
  const manifest = {
23
99
  $schema: 'https://anby.dev/schemas/app-manifest.v1.json',
24
- id,
100
+ id: opts.id,
25
101
  version: '1.0.0',
26
- name,
27
- description: `${name} — submitted via @anby/cli`,
102
+ name: opts.name,
103
+ description: `${opts.name} — submitted via @anby/cli`,
28
104
  icon: '📦',
29
105
  color: '#E63426',
30
106
  runtime: {
31
107
  type: 'remix',
32
- port,
108
+ port: opts.port,
33
109
  healthCheck: '/api/health',
34
110
  readyCheck: '/api/health',
35
111
  },
36
112
  frontend: {
37
113
  type: 'iframe',
38
- routes: [{ path: '/', label: name, icon: '📦' }],
114
+ routes: [{ path: '/', label: opts.name, icon: '📦' }],
39
115
  navPosition: 'sidebar',
40
116
  },
41
117
  provides: { entities: [], events: [] },
@@ -49,7 +125,353 @@ export async function initCommand(options) {
49
125
  database: { type: 'postgresql' },
50
126
  };
51
127
  await writeFile(target, JSON.stringify(manifest, null, 2) + '\n', 'utf-8');
52
- console.log(kleur.green(`✔ Wrote ${target}`));
53
- console.log(kleur.dim(` Next: anby app validate && anby app publish --public-url http://localhost:${port}`));
128
+ console.log(kleur.green(`✔ Wrote anby-app.manifest.json`));
129
+ }
130
+ // ── Step 2: Vite config ───────────────────────────────────────────────
131
+ async function patchViteConfig() {
132
+ const candidates = [
133
+ 'vite.config.ts',
134
+ 'vite.config.mts',
135
+ 'vite.config.js',
136
+ 'vite.config.mjs',
137
+ ];
138
+ let target = null;
139
+ for (const name of candidates) {
140
+ try {
141
+ await access(resolve(name));
142
+ target = name;
143
+ break;
144
+ }
145
+ catch {
146
+ // try next
147
+ }
148
+ }
149
+ if (!target) {
150
+ console.log(kleur.dim('• No vite.config.* found — skipping plugin wiring. Add `anbyVitePlugin()` from `@anby/platform-sdk/vite` to your bundler manually.'));
151
+ return;
152
+ }
153
+ const path = resolve(target);
154
+ const original = await readFile(path, 'utf-8');
155
+ if (original.includes('anbyVitePlugin')) {
156
+ console.log(kleur.dim(`• ${target} already wires anbyVitePlugin — no patch needed`));
157
+ return;
158
+ }
159
+ const importLine = "import { anbyVitePlugin } from '@anby/platform-sdk/vite';";
160
+ const importRegex = /^import .+ from .+;?\s*$/gm;
161
+ let lastImportEnd = -1;
162
+ for (const match of original.matchAll(importRegex)) {
163
+ if (match.index !== undefined) {
164
+ lastImportEnd = match.index + match[0].length;
165
+ }
166
+ }
167
+ let withImport;
168
+ if (lastImportEnd >= 0) {
169
+ withImport =
170
+ original.slice(0, lastImportEnd) +
171
+ '\n' +
172
+ importLine +
173
+ original.slice(lastImportEnd);
174
+ }
175
+ else {
176
+ withImport = importLine + '\n' + original;
177
+ }
178
+ const pluginsArrayRegex = /(plugins\s*:\s*\[)(\s*)/;
179
+ if (!pluginsArrayRegex.test(withImport)) {
180
+ console.log(kleur.yellow(`! Could not find a \`plugins: [...]\` array in ${target}. ` +
181
+ `Add ${kleur.cyan('anbyVitePlugin()')} to your plugins manually.`));
182
+ return;
183
+ }
184
+ const patched = withImport.replace(pluginsArrayRegex, (_, head, ws) => `${head}${ws}anbyVitePlugin(),${ws}`);
185
+ await writeFile(path, patched, 'utf-8');
186
+ console.log(kleur.green(`✔ Patched ${target} to load anbyVitePlugin`));
187
+ }
188
+ // ── Step 3: .gitignore ────────────────────────────────────────────────
189
+ async function patchGitignore() {
190
+ const path = resolve('.gitignore');
191
+ let existing = '';
192
+ try {
193
+ existing = await readFile(path, 'utf-8');
194
+ }
195
+ catch {
196
+ // file doesn't exist — we'll create it below
197
+ }
198
+ const lines = existing.split(/\r?\n/).map((l) => l.trim());
199
+ const needsPublicAnby = !lines.some((l) => l === 'public/_anby/' || l === 'public/_anby');
200
+ const needsDotAnby = !lines.some((l) => l === '.anby/' || l === '.anby');
201
+ if (!needsPublicAnby && !needsDotAnby) {
202
+ console.log(kleur.dim('• .gitignore already covers Anby paths — no change'));
203
+ return;
204
+ }
205
+ let block = '';
206
+ if (needsPublicAnby || needsDotAnby) {
207
+ block +=
208
+ (existing.length === 0 || existing.endsWith('\n') ? '' : '\n') +
209
+ '\n# Anby — auto-generated files (do not commit)\n';
210
+ if (needsPublicAnby)
211
+ block += 'public/_anby/\n';
212
+ if (needsDotAnby)
213
+ block += '.anby/\n';
214
+ }
215
+ await writeFile(path, existing + block, 'utf-8');
216
+ console.log(kleur.green('✔ Updated .gitignore for Anby paths'));
217
+ }
218
+ // ── Step 4: auth.server.ts scaffold ───────────────────────────────────
219
+ const AUTH_SERVER_TEMPLATE = `/**
220
+ * Auth utilities — auto-generated by \`anby init\`.
221
+ *
222
+ * Uses @anby/platform-sdk for authentication.
223
+ * Supports RS256 JWT (browser/Bearer/cookie) + HMAC (service-to-service).
224
+ * Extracts tenantId from JWT payload.
225
+ */
226
+
227
+ import {
228
+ bootstrapFromToken,
229
+ authenticateRequest as sdkAuthenticate,
230
+ requireAuth as sdkRequireAuth,
231
+ type AuthUser,
232
+ } from '@anby/platform-sdk';
233
+
234
+ const ANBY_APP_TOKEN = process.env.ANBY_APP_TOKEN || '';
235
+
236
+ if (!ANBY_APP_TOKEN) {
237
+ throw new Error(
238
+ 'ANBY_APP_TOKEN is required. Run \\\`anby login && anby init\\\` to generate one.',
239
+ );
240
+ }
241
+
242
+ let _bootstrapPromise: Promise<void> | null = null;
243
+
244
+ /**
245
+ * Initialize the SDK by bootstrapping from ANBY_APP_TOKEN. Returns a
246
+ * promise that resolves when discovery + auth public key are fetched
247
+ * and the SDK is ready to verify tokens. Idempotent.
248
+ */
249
+ export function initAuth(): Promise<void> {
250
+ if (_bootstrapPromise) return _bootstrapPromise;
251
+ _bootstrapPromise = bootstrapFromToken({ appToken: ANBY_APP_TOKEN }).catch(
252
+ (err) => {
253
+ _bootstrapPromise = null;
254
+ throw err;
255
+ },
256
+ );
257
+ return _bootstrapPromise;
258
+ }
259
+
260
+ // Kick off bootstrap at module load.
261
+ initAuth().catch((err) => {
262
+ console.error('[anby] bootstrap failed at module load:', err);
263
+ });
264
+
265
+ export type { AuthUser };
266
+
267
+ /**
268
+ * Authenticate a request via JWT or HMAC.
269
+ * Returns the authenticated user with tenantId or null.
270
+ */
271
+ export function authenticateRequest(request: Request): AuthUser | null {
272
+ return sdkAuthenticate(request);
273
+ }
274
+
275
+ /**
276
+ * Require authentication — throws 401 if not authenticated.
277
+ */
278
+ export function requireAuth(request: Request): AuthUser {
279
+ return sdkRequireAuth(request);
280
+ }
281
+
282
+ /**
283
+ * Extract tenantId from the authenticated user.
284
+ * Falls back to 'default' if not present.
285
+ */
286
+ export function getTenantId(request: Request): string {
287
+ const user = authenticateRequest(request);
288
+ return user?.tenantId || 'default';
289
+ }
290
+ `;
291
+ async function scaffoldAuthServer() {
292
+ const appDir = resolve('app');
293
+ try {
294
+ await access(appDir);
295
+ }
296
+ catch {
297
+ console.log(kleur.dim('• No app/ directory found (not a Remix project?) — skipping auth.server.ts scaffold'));
298
+ return;
299
+ }
300
+ const libDir = resolve('app/lib');
301
+ const target = resolve('app/lib/auth.server.ts');
302
+ try {
303
+ await access(target);
304
+ console.log(kleur.dim(`• app/lib/auth.server.ts already exists — leaving it alone`));
305
+ return;
306
+ }
307
+ catch {
308
+ // ok — file doesn't exist, we'll create it
309
+ }
310
+ await mkdir(libDir, { recursive: true });
311
+ await writeFile(target, AUTH_SERVER_TEMPLATE, 'utf-8');
312
+ console.log(kleur.green('✔ Scaffolded app/lib/auth.server.ts'));
313
+ }
314
+ // ── Step 5: Patch entry.server.tsx ────────────────────────────────────
315
+ async function patchEntryServer(port) {
316
+ const target = resolve('app/entry.server.tsx');
317
+ let original;
318
+ try {
319
+ original = await readFile(target, 'utf-8');
320
+ }
321
+ catch {
322
+ console.log(kleur.dim('• No app/entry.server.tsx found — skipping entry patch.'));
323
+ return;
324
+ }
325
+ if (original.includes('initAuth')) {
326
+ console.log(kleur.dim('• app/entry.server.tsx already has initAuth — no patch needed'));
327
+ return;
328
+ }
329
+ const sdkImport = "import { autoPublishOnBoot } from '@anby/platform-sdk';";
330
+ const authImport = "import { initAuth } from './lib/auth.server';";
331
+ const importRegex = /^import .+ from .+;?\s*$/gm;
332
+ let lastImportEnd = -1;
333
+ for (const match of original.matchAll(importRegex)) {
334
+ if (match.index !== undefined) {
335
+ lastImportEnd = match.index + match[0].length;
336
+ }
337
+ }
338
+ let withImports;
339
+ if (lastImportEnd >= 0) {
340
+ withImports =
341
+ original.slice(0, lastImportEnd) +
342
+ '\n' +
343
+ sdkImport +
344
+ '\n' +
345
+ authImport +
346
+ original.slice(lastImportEnd);
347
+ }
348
+ else {
349
+ withImports = sdkImport + '\n' + authImport + '\n' + original;
350
+ }
351
+ const bootstrapBlock = `
352
+ // Anby platform bootstrap — auto-generated by \`anby init\`.
353
+ // Ensures auth + discovery are ready before the first request.
354
+ await initAuth();
355
+ autoPublishOnBoot({
356
+ publicUrl: process.env.APP_PUBLIC_URL || \`http://localhost:\${process.env.PORT || ${port}}\`,
357
+ });
358
+ `;
359
+ const exportRegex = /^export\s+(default|function|async\s+function)/m;
360
+ const exportMatch = withImports.match(exportRegex);
361
+ let patched;
362
+ if (exportMatch && exportMatch.index !== undefined) {
363
+ patched =
364
+ withImports.slice(0, exportMatch.index) +
365
+ bootstrapBlock +
366
+ '\n' +
367
+ withImports.slice(exportMatch.index);
368
+ }
369
+ else {
370
+ patched = withImports + '\n' + bootstrapBlock;
371
+ }
372
+ await writeFile(target, patched, 'utf-8');
373
+ console.log(kleur.green('✔ Patched app/entry.server.tsx (initAuth + autoPublishOnBoot)'));
374
+ }
375
+ // ── Step 6: Self-register with registry ───────────────────────────────
376
+ async function registerAndWriteToken(opts) {
377
+ if (!opts.auth) {
378
+ console.log(kleur.yellow('! Not logged in — run `anby login` first, then `anby init` again'));
379
+ return;
380
+ }
381
+ // Check if .env.local already has ANBY_APP_TOKEN
382
+ const envLocalPath = resolve('.env.local');
383
+ try {
384
+ const envContent = await readFile(envLocalPath, 'utf-8');
385
+ if (envContent.includes('ANBY_APP_TOKEN=')) {
386
+ console.log(kleur.dim('• .env.local already contains ANBY_APP_TOKEN — skipping registration'));
387
+ return;
388
+ }
389
+ }
390
+ catch {
391
+ // .env.local doesn't exist — fine
392
+ }
393
+ // Load the manifest we just wrote
394
+ let manifest;
395
+ try {
396
+ const raw = await readFile(resolve('anby-app.manifest.json'), 'utf-8');
397
+ manifest = JSON.parse(raw);
398
+ }
399
+ catch {
400
+ console.log(kleur.yellow('! Could not read anby-app.manifest.json — skipping registration'));
401
+ return;
402
+ }
403
+ const publicUrl = `http://localhost:${opts.port}`;
404
+ const registryUrl = `${opts.registryBase}/registry/apps`;
405
+ // Register with a minimal manifest (just metadata, no entities).
406
+ // Entity declarations are published later by autoPublishOnBoot when
407
+ // the developer runs `npm run dev` — by then they've had time to
408
+ // edit the manifest with the correct provides/requires.
409
+ const registrationManifest = {
410
+ ...manifest,
411
+ provides: { entities: [], events: [] },
412
+ requires: { ...manifest.requires, entities: [], events: [] },
413
+ };
414
+ const body = {
415
+ id: manifest.id,
416
+ name: manifest.name,
417
+ description: manifest.description,
418
+ icon: manifest.icon,
419
+ color: manifest.color,
420
+ publisherId: manifest.id.split('.').slice(0, 2).join('.'),
421
+ version: manifest.version,
422
+ publicUrl,
423
+ submittedBy: `cli:${opts.auth.email}`,
424
+ manifest: registrationManifest,
425
+ };
426
+ let res;
427
+ try {
428
+ res = await fetch(registryUrl, {
429
+ method: 'POST',
430
+ headers: {
431
+ 'Content-Type': 'application/json',
432
+ Authorization: `Bearer ${opts.auth.token}`,
433
+ },
434
+ body: JSON.stringify(body),
435
+ signal: AbortSignal.timeout(10_000),
436
+ });
437
+ }
438
+ catch (err) {
439
+ console.log(kleur.yellow(`! Could not reach registry at ${registryUrl}: ${err.message}`));
440
+ return;
441
+ }
442
+ if (!res.ok) {
443
+ const errBody = await res.text();
444
+ console.log(kleur.yellow(`! Registry rejected publish (${res.status}): ${errBody}`));
445
+ return;
446
+ }
447
+ const result = await res.json();
448
+ if (!result.privateKey) {
449
+ console.log(kleur.dim('• App already registered (no new private key). Run `anby app rotate-token` for a new token.'));
450
+ return;
451
+ }
452
+ // Assemble token — platformUrl is the registry base (used by SDK discovery)
453
+ const token = assembleToken({
454
+ appId: manifest.id,
455
+ platformUrl: opts.registryBase,
456
+ privateKey: result.privateKey,
457
+ });
458
+ // Write to .env.local
459
+ let envContent = '';
460
+ try {
461
+ envContent = await readFile(envLocalPath, 'utf-8');
462
+ }
463
+ catch {
464
+ // File doesn't exist
465
+ }
466
+ const newLines = [
467
+ ...(envContent ? [] : ['# Auto-generated by anby init']),
468
+ `ANBY_APP_TOKEN=${token}`,
469
+ `APP_PUBLIC_URL=http://localhost:${opts.port}`,
470
+ ];
471
+ const separator = envContent.length === 0 || envContent.endsWith('\n') ? '' : '\n';
472
+ const appended = envContent + separator + newLines.join('\n') + '\n';
473
+ await writeFile(envLocalPath, appended, { mode: 0o600 });
474
+ console.log(kleur.green('✔ Registered app with registry'));
475
+ console.log(kleur.green('✔ Wrote ANBY_APP_TOKEN to .env.local'));
54
476
  }
55
477
  //# sourceMappingURL=init.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,KAAK,MAAM,OAAO,CAAC;AAQ1B;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,OAAoB;IACpD,MAAM,MAAM,GAAG,OAAO,CAAC,wBAAwB,CAAC,CAAC;IAEjD,IAAI,CAAC;QACH,MAAM,MAAM,CAAC,MAAM,CAAC,CAAC;QACrB,OAAO,CAAC,KAAK,CACX,KAAK,CAAC,GAAG,CAAC,KAAK,MAAM,yCAAyC,CAAC,CAChE,CAAC;QACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAAC,MAAM,CAAC;QACP,0BAA0B;IAC5B,CAAC;IAED,MAAM,EAAE,GAAG,OAAO,CAAC,EAAE,IAAI,oBAAoB,CAAC;IAC9C,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,IAAI,QAAQ,CAAC;IACtC,MAAM,IAAI,GAAG,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,IAAI,MAAM,EAAE,EAAE,CAAC,CAAC;IAEzD,MAAM,QAAQ,GAAG;QACf,OAAO,EAAE,+CAA+C;QACxD,EAAE;QACF,OAAO,EAAE,OAAO;QAChB,IAAI;QACJ,WAAW,EAAE,GAAG,IAAI,4BAA4B;QAChD,IAAI,EAAE,IAAI;QACV,KAAK,EAAE,SAAS;QAChB,OAAO,EAAE;YACP,IAAI,EAAE,OAAO;YACb,IAAI;YACJ,WAAW,EAAE,aAAa;YAC1B,UAAU,EAAE,aAAa;SAC1B;QACD,QAAQ,EAAE;YACR,IAAI,EAAE,QAAQ;YACd,MAAM,EAAE,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;YAChD,WAAW,EAAE,SAAS;SACvB;QACD,QAAQ,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE;QACtC,QAAQ,EAAE;YACR,QAAQ,EAAE,CAAC,MAAM,CAAC;YAClB,QAAQ,EAAE,EAAE;YACZ,MAAM,EAAE,EAAE;YACV,QAAQ,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE;SACvC;QACD,WAAW,EAAE,CAAC,gBAAgB,CAAC;QAC/B,QAAQ,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE;KACjC,CAAC;IAEF,MAAM,SAAS,CAAC,MAAM,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,EAAE,OAAO,CAAC,CAAC;IAC3E,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,WAAW,MAAM,EAAE,CAAC,CAAC,CAAC;IAC9C,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,+EAA+E,IAAI,EAAE,CAAC,CAAC,CAAC;AAChH,CAAC"}
1
+ {"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ interface LoginOptions {
2
+ /** Hidden override for platform devs (--auth-url) */
3
+ authUrl?: string;
4
+ }
5
+ /**
6
+ * `anby login` — authenticate with the Anby platform via Google OAuth.
7
+ *
8
+ * Default auth URL: https://auth.anby.ai
9
+ * Platform devs can override with: anby login --auth-url http://localhost:3000
10
+ */
11
+ export declare function loginCommand(options: LoginOptions): Promise<void>;
12
+ export {};
@@ -0,0 +1,112 @@
1
+ import { createServer } from 'node:http';
2
+ import { URL } from 'node:url';
3
+ import kleur from 'kleur';
4
+ import { saveAuth, getStoredAuth } from '../lib/auth-store.js';
5
+ const DEFAULT_AUTH_URL = 'https://auth.anby.ai';
6
+ /**
7
+ * `anby login` — authenticate with the Anby platform via Google OAuth.
8
+ *
9
+ * Default auth URL: https://auth.anby.ai
10
+ * Platform devs can override with: anby login --auth-url http://localhost:3000
11
+ */
12
+ export async function loginCommand(options) {
13
+ const existing = await getStoredAuth();
14
+ if (existing) {
15
+ console.log(kleur.dim(`Already logged in as ${existing.email}`));
16
+ console.log(kleur.dim('Run `anby logout` to sign out first.'));
17
+ return;
18
+ }
19
+ const authUrl = (options.authUrl ||
20
+ process.env.ANBY_AUTH_URL ||
21
+ DEFAULT_AUTH_URL).replace(/\/+$/, '');
22
+ const { token, email } = await runOAuthFlow(authUrl);
23
+ // JWT exp is 7 days from issuance.
24
+ const payload = JSON.parse(Buffer.from(token.split('.')[1], 'base64url').toString());
25
+ const expiresAt = new Date(payload.exp * 1000).toISOString();
26
+ await saveAuth({ token, email: email || payload.email || 'unknown', expiresAt });
27
+ console.log('');
28
+ console.log(kleur.green(`✔ Logged in as ${email || payload.email}`));
29
+ console.log(kleur.dim(` Token expires: ${expiresAt}`));
30
+ }
31
+ function runOAuthFlow(authUrl) {
32
+ return new Promise((resolve, reject) => {
33
+ const server = createServer((req, res) => {
34
+ const url = new URL(req.url || '/', `http://localhost`);
35
+ if (url.pathname === '/callback') {
36
+ const token = url.searchParams.get('token');
37
+ const email = url.searchParams.get('email') || '';
38
+ const error = url.searchParams.get('error');
39
+ if (error || !token) {
40
+ res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
41
+ res.end(errorPage(error || 'no_token'));
42
+ server.close();
43
+ reject(new Error(`Login failed: ${error || 'no token received'}`));
44
+ return;
45
+ }
46
+ res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
47
+ res.end(successPage());
48
+ server.close();
49
+ resolve({ token, email });
50
+ return;
51
+ }
52
+ res.writeHead(404);
53
+ res.end('Not found');
54
+ });
55
+ server.listen(0, '127.0.0.1', () => {
56
+ const addr = server.address();
57
+ if (!addr || typeof addr === 'string') {
58
+ reject(new Error('Failed to bind local server'));
59
+ return;
60
+ }
61
+ const callbackUrl = `http://localhost:${addr.port}/callback`;
62
+ const loginUrl = `${authUrl}/auth/google?returnUrl=${encodeURIComponent(callbackUrl)}&mode=cli`;
63
+ console.log(kleur.dim(`Opening browser for login...`));
64
+ console.log(kleur.dim(`If the browser doesn't open, visit:`));
65
+ console.log(kleur.cyan(loginUrl));
66
+ console.log('');
67
+ openBrowser(loginUrl).catch(() => {
68
+ // Browser didn't open — user can copy the URL above.
69
+ });
70
+ });
71
+ // Timeout after 3 minutes
72
+ setTimeout(() => {
73
+ server.close();
74
+ reject(new Error('Login timed out after 3 minutes'));
75
+ }, 180_000);
76
+ });
77
+ }
78
+ async function openBrowser(url) {
79
+ const { exec } = await import('node:child_process');
80
+ const { promisify } = await import('node:util');
81
+ const execAsync = promisify(exec);
82
+ const platform = process.platform;
83
+ if (platform === 'darwin') {
84
+ await execAsync(`open "${url}"`);
85
+ }
86
+ else if (platform === 'win32') {
87
+ await execAsync(`start "" "${url}"`);
88
+ }
89
+ else {
90
+ await execAsync(`xdg-open "${url}"`);
91
+ }
92
+ }
93
+ function successPage() {
94
+ return `<!DOCTYPE html>
95
+ <html><head><meta charset="utf-8"><title>Anby CLI</title></head>
96
+ <body style="font-family:system-ui;display:flex;align-items:center;justify-content:center;min-height:100vh;margin:0;background:#0a0a0a;color:#fafafa">
97
+ <div style="text-align:center">
98
+ <h1 style="color:#22c55e">✔ Logged in</h1>
99
+ <p>You can close this tab and return to the terminal.</p>
100
+ </div></body></html>`;
101
+ }
102
+ function errorPage(error) {
103
+ return `<!DOCTYPE html>
104
+ <html><head><meta charset="utf-8"><title>Anby CLI</title></head>
105
+ <body style="font-family:system-ui;display:flex;align-items:center;justify-content:center;min-height:100vh;margin:0;background:#0a0a0a;color:#fafafa">
106
+ <div style="text-align:center">
107
+ <h1 style="color:#ef4444">✖ Login failed</h1>
108
+ <p>${error}</p>
109
+ <p>Return to the terminal and try again.</p>
110
+ </div></body></html>`;
111
+ }
112
+ //# 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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"}
@@ -0,0 +1 @@
1
+ export declare function logoutCommand(): Promise<void>;
@@ -0,0 +1,7 @@
1
+ import kleur from 'kleur';
2
+ import { clearAuth } from '../lib/auth-store.js';
3
+ export async function logoutCommand() {
4
+ await clearAuth();
5
+ console.log(kleur.green('✔ Logged out'));
6
+ }
7
+ //# sourceMappingURL=logout.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logout.js","sourceRoot":"","sources":["../../src/commands/logout.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAEjD,MAAM,CAAC,KAAK,UAAU,aAAa;IACjC,MAAM,SAAS,EAAE,CAAC;IAClB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC,CAAC;AAC3C,CAAC"}
@@ -4,6 +4,17 @@ interface PublishOptions {
4
4
  publicUrl?: string;
5
5
  changelog?: string;
6
6
  featured?: boolean;
7
+ /**
8
+ * If set, the CLI writes the assembled ANBY_APP_TOKEN to this path
9
+ * (e.g. ".env.local"). Without this flag the token is only printed
10
+ * to stdout — the dev is responsible for capturing it.
11
+ */
12
+ saveTo?: string;
13
+ /**
14
+ * Override the platform base URL embedded in the token. Defaults to
15
+ * the registry URL with the /registry suffix stripped.
16
+ */
17
+ platformUrl?: string;
7
18
  }
8
19
  export declare function publishCommand(options: PublishOptions): Promise<void>;
9
20
  export {};
@@ -1,5 +1,7 @@
1
1
  import kleur from 'kleur';
2
+ import { writeFile } from 'node:fs/promises';
2
3
  import { publishAppFromManifest } from '@anby/platform-sdk';
4
+ import { assembleToken } from '../lib/token.js';
3
5
  export async function publishCommand(options) {
4
6
  const result = await publishAppFromManifest({
5
7
  manifestPath: options.manifest,
@@ -16,5 +18,39 @@ export async function publishCommand(options) {
16
18
  if (result.app.publicUrl) {
17
19
  console.log(kleur.dim(` publicUrl: ${result.app.publicUrl}`));
18
20
  }
21
+ // PLAN-app-bootstrap PR3: assemble + print ANBY_APP_TOKEN if the registry
22
+ // returned a fresh private key (only happens on first publish for an app).
23
+ if (result.privateKey) {
24
+ const platformUrl = options.platformUrl ?? options.registry.replace(/\/registry\/?$/, '');
25
+ const token = assembleToken({
26
+ appId: result.app.id,
27
+ platformUrl,
28
+ privateKey: result.privateKey,
29
+ });
30
+ console.log('');
31
+ console.log(kleur.bold().yellow('━━━ ANBY_APP_TOKEN (shown ONCE — store it safely) ━━━'));
32
+ console.log('');
33
+ console.log(token);
34
+ console.log('');
35
+ console.log(kleur.dim('Paste this into your app environment as ANBY_APP_TOKEN.\n' +
36
+ 'It contains your app signing key. Treat it as a secret.\n' +
37
+ 'If you lose it, run `anby app rotate-token <appId>` to issue a new one.'));
38
+ console.log(kleur.bold().yellow('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'));
39
+ if (options.saveTo) {
40
+ const envLine = `ANBY_APP_TOKEN=${token}\n`;
41
+ try {
42
+ await writeFile(options.saveTo, envLine, { mode: 0o600 });
43
+ console.log(kleur.green(`✔ Token written to ${options.saveTo}`));
44
+ }
45
+ catch (err) {
46
+ console.error(kleur.red(`✖ Failed to write token to ${options.saveTo}: ${err.message}`));
47
+ process.exit(1);
48
+ }
49
+ }
50
+ }
51
+ else {
52
+ console.log(kleur.dim('(No new ANBY_APP_TOKEN issued — this app already has a registered keypair.\n' +
53
+ ' To rotate, run `anby app rotate-token ' + result.app.id + '`.)'));
54
+ }
19
55
  }
20
56
  //# sourceMappingURL=publish.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"publish.js","sourceRoot":"","sources":["../../src/commands/publish.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;AAU5D,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,OAAuB;IAC1D,MAAM,MAAM,GAAG,MAAM,sBAAsB,CAAC;QAC1C,YAAY,EAAE,OAAO,CAAC,QAAQ;QAC9B,WAAW,EAAE,OAAO,CAAC,QAAQ;QAC7B,SAAS,EAAE,OAAO,CAAC,SAAS;QAC5B,SAAS,EAAE,OAAO,CAAC,SAAS;QAC5B,QAAQ,EAAE,OAAO,CAAC,QAAQ;KAC3B,CAAC,CAAC;IAEH,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,8BAA8B,CAAC,CAAC,CAAC;QACzD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,OAAO,CAAC,GAAG,CACT,KAAK,CAAC,KAAK,CACT,eAAe,MAAM,CAAC,GAAG,CAAC,EAAE,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,YAAY,MAAM,CAAC,GAAG,CAAC,MAAM,GAAG,CACvF,CACF,CAAC;IACF,IAAI,MAAM,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC;QACzB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,gBAAgB,MAAM,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC;IACjE,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"publish.js","sourceRoot":"","sources":["../../src/commands/publish.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ export interface StoredAuth {
2
+ token: string;
3
+ email: string;
4
+ expiresAt: string;
5
+ }
6
+ /**
7
+ * Read stored CLI credentials from ~/.anby/auth.json.
8
+ * Returns null if the file doesn't exist or the token has expired.
9
+ */
10
+ export declare function getStoredAuth(): Promise<StoredAuth | null>;
11
+ /**
12
+ * Persist CLI credentials to ~/.anby/auth.json (0600).
13
+ */
14
+ export declare function saveAuth(auth: StoredAuth): Promise<void>;
15
+ /**
16
+ * Remove stored credentials.
17
+ */
18
+ export declare function clearAuth(): Promise<void>;
19
+ /**
20
+ * Extract email domain from stored auth.
21
+ * e.g. "user@bravebits.vn" → "bravebits.vn"
22
+ */
23
+ export declare function getEmailDomain(email: string): string;
@@ -0,0 +1,53 @@
1
+ import { readFile, writeFile, mkdir } from 'node:fs/promises';
2
+ import { homedir } from 'node:os';
3
+ import { join } from 'node:path';
4
+ const ANBY_DIR = join(homedir(), '.anby');
5
+ const AUTH_FILE = join(ANBY_DIR, 'auth.json');
6
+ /**
7
+ * Read stored CLI credentials from ~/.anby/auth.json.
8
+ * Returns null if the file doesn't exist or the token has expired.
9
+ */
10
+ export async function getStoredAuth() {
11
+ try {
12
+ const raw = await readFile(AUTH_FILE, 'utf-8');
13
+ const data = JSON.parse(raw);
14
+ if (!data.token)
15
+ return null;
16
+ if (new Date(data.expiresAt) < new Date())
17
+ return null;
18
+ return data;
19
+ }
20
+ catch {
21
+ return null;
22
+ }
23
+ }
24
+ /**
25
+ * Persist CLI credentials to ~/.anby/auth.json (0600).
26
+ */
27
+ export async function saveAuth(auth) {
28
+ await mkdir(ANBY_DIR, { recursive: true });
29
+ await writeFile(AUTH_FILE, JSON.stringify(auth, null, 2) + '\n', {
30
+ mode: 0o600,
31
+ });
32
+ }
33
+ /**
34
+ * Remove stored credentials.
35
+ */
36
+ export async function clearAuth() {
37
+ try {
38
+ const { unlink } = await import('node:fs/promises');
39
+ await unlink(AUTH_FILE);
40
+ }
41
+ catch {
42
+ // Already gone — fine.
43
+ }
44
+ }
45
+ /**
46
+ * Extract email domain from stored auth.
47
+ * e.g. "user@bravebits.vn" → "bravebits.vn"
48
+ */
49
+ export function getEmailDomain(email) {
50
+ const parts = email.split('@');
51
+ return parts[1] || 'example.com';
52
+ }
53
+ //# sourceMappingURL=auth-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth-store.js","sourceRoot":"","sources":["../../src/lib/auth-store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAC9D,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,OAAO,CAAC,CAAC;AAC1C,MAAM,SAAS,GAAG,IAAI,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC;AAQ9C;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa;IACjC,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;QAC/C,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAe,CAAC;QAC3C,IAAI,CAAC,IAAI,CAAC,KAAK;YAAE,OAAO,IAAI,CAAC;QAC7B,IAAI,IAAI,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,IAAI,IAAI,EAAE;YAAE,OAAO,IAAI,CAAC;QACvD,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,IAAgB;IAC7C,MAAM,KAAK,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC3C,MAAM,SAAS,CAAC,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,EAAE;QAC/D,IAAI,EAAE,KAAK;KACZ,CAAC,CAAC;AACL,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS;IAC7B,IAAI,CAAC;QACH,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,MAAM,CAAC,kBAAkB,CAAC,CAAC;QACpD,MAAM,MAAM,CAAC,SAAS,CAAC,CAAC;IAC1B,CAAC;IAAC,MAAM,CAAC;QACP,uBAAuB;IACzB,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,cAAc,CAAC,KAAa;IAC1C,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC/B,OAAO,KAAK,CAAC,CAAC,CAAC,IAAI,aAAa,CAAC;AACnC,CAAC"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * ANBY_APP_TOKEN assembly helper.
3
+ *
4
+ * Mirrors the parser in @anby/platform-sdk/src/bootstrap. Kept in the CLI
5
+ * (rather than imported from the SDK) so the CLI doesn't have to ship the
6
+ * SDK's whole runtime just for one base64 wrapper.
7
+ *
8
+ * Format: anby_v1_<base64url(json)>
9
+ * json = { v: 1, appId, platformUrl, privateKey }
10
+ */
11
+ export declare const ANBY_TOKEN_PREFIX = "anby_v1_";
12
+ export interface AssembleTokenInput {
13
+ appId: string;
14
+ platformUrl: string;
15
+ privateKey: string;
16
+ }
17
+ export declare function assembleToken(input: AssembleTokenInput): string;
@@ -0,0 +1,27 @@
1
+ /**
2
+ * ANBY_APP_TOKEN assembly helper.
3
+ *
4
+ * Mirrors the parser in @anby/platform-sdk/src/bootstrap. Kept in the CLI
5
+ * (rather than imported from the SDK) so the CLI doesn't have to ship the
6
+ * SDK's whole runtime just for one base64 wrapper.
7
+ *
8
+ * Format: anby_v1_<base64url(json)>
9
+ * json = { v: 1, appId, platformUrl, privateKey }
10
+ */
11
+ export const ANBY_TOKEN_PREFIX = 'anby_v1_';
12
+ export function assembleToken(input) {
13
+ if (!input.appId || !input.platformUrl || !input.privateKey) {
14
+ throw new Error('assembleToken: appId, platformUrl, and privateKey are required');
15
+ }
16
+ if (!input.privateKey.includes('PRIVATE KEY')) {
17
+ throw new Error('assembleToken: privateKey must be a PEM');
18
+ }
19
+ const payload = {
20
+ v: 1,
21
+ appId: input.appId,
22
+ platformUrl: input.platformUrl.replace(/\/$/, ''),
23
+ privateKey: input.privateKey,
24
+ };
25
+ return ANBY_TOKEN_PREFIX + Buffer.from(JSON.stringify(payload)).toString('base64url');
26
+ }
27
+ //# sourceMappingURL=token.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"token.js","sourceRoot":"","sources":["../../src/lib/token.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,MAAM,CAAC,MAAM,iBAAiB,GAAG,UAAU,CAAC;AAQ5C,MAAM,UAAU,aAAa,CAAC,KAAyB;IACrD,IAAI,CAAC,KAAK,CAAC,KAAK,IAAI,CAAC,KAAK,CAAC,WAAW,IAAI,CAAC,KAAK,CAAC,UAAU,EAAE,CAAC;QAC5D,MAAM,IAAI,KAAK,CAAC,gEAAgE,CAAC,CAAC;IACpF,CAAC;IACD,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,QAAQ,CAAC,aAAa,CAAC,EAAE,CAAC;QAC9C,MAAM,IAAI,KAAK,CAAC,yCAAyC,CAAC,CAAC;IAC7D,CAAC;IACD,MAAM,OAAO,GAAG;QACd,CAAC,EAAE,CAAU;QACb,KAAK,EAAE,KAAK,CAAC,KAAK;QAClB,WAAW,EAAE,KAAK,CAAC,WAAW,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC;QACjD,UAAU,EAAE,KAAK,CAAC,UAAU;KAC7B,CAAC;IACF,OAAO,iBAAiB,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;AACxF,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@anby/cli",
3
- "version": "0.1.1",
3
+ "version": "0.8.0",
4
4
  "description": "Anby Platform CLI — scaffold, validate, publish, and install Anby apps",
5
5
  "keywords": [
6
6
  "anby",
@@ -43,7 +43,7 @@
43
43
  },
44
44
  "dependencies": {
45
45
  "@anby/manifest-schema": "^0.1.1",
46
- "@anby/platform-sdk": "^0.1.1",
46
+ "@anby/platform-sdk": "^0.8.0",
47
47
  "commander": "^12.1.0",
48
48
  "kleur": "^4.1.5"
49
49
  },