@anby/cli 0.7.0 → 0.9.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.
@@ -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;
@@ -4,19 +4,39 @@ import { publishCommand } from './publish.js';
4
4
  import { installCommand } from './install.js';
5
5
  import { listCommand } from './list.js';
6
6
  import { codegenCommand } from './codegen.js';
7
+ import { loginCommand } from './login.js';
8
+ import { logoutCommand } from './logout.js';
7
9
  /**
8
10
  * All app-lifecycle commands live under `anby app <verb>` so we can add
9
11
  * other command namespaces later (`anby tenant`, `anby events`, etc.)
10
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.
11
17
  */
12
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);
13
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);
14
36
  app
15
37
  .command('init')
16
- .description('Scaffold a new anby-app.manifest.json in the current directory')
17
- .option('--id <id>', 'Reverse-domain app id, e.g. com.bravebits.hello')
18
- .option('--name <name>', 'Human-readable app name')
19
- .option('--port <port>', 'Runtime port', '3099')
38
+ .description('Scaffold and register an Anby app (interactive)')
39
+ .option('--registry-url <url>', '[dev] Override registry URL')
20
40
  .action(initCommand);
21
41
  app
22
42
  .command('validate')
@@ -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;AACxC,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAE9C;;;;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,kBAAkB,EAAE,mEAAmE,CAAC;SAC/F,MAAM,CAAC,sBAAsB,EAAE,yGAAyG,CAAC;SACzI,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;IAEvB,GAAG;SACA,OAAO,CAAC,SAAS,CAAC;SAClB,WAAW,CAAC,0EAA0E,CAAC;SACvF,MAAM,CAAC,mBAAmB,EAAE,uBAAuB,EAAE,0BAA0B,CAAC;SAChF,MAAM,CAAC,cAAc,EAAE,iCAAiC,EAAE,oBAAoB,CAAC;SAC/E,MAAM,CAAC,SAAS,EAAE,6CAA6C,CAAC;SAChE,MAAM,CAAC,cAAc,CAAC,CAAC;AAC5B,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/commands/index.ts"],"names":[],"mappings":"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"}
@@ -1,22 +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
- * One-stop project bootstrap for an Anby app.
6
+ * `anby init` interactive scaffold + register.
8
7
  *
9
- * Run once after `npm create remix` (or any Vite-based stack):
10
- *
11
- * 1. Writes `anby-app.manifest.json` skeleton
12
- * 2. Patches `vite.config.ts` to load `anbyVitePlugin()` from
13
- * `@anby/platform-sdk/vite` (idempotent — skips if already wired)
14
- * 3. Adds `public/_anby/` to `.gitignore`
15
- *
16
- * After this single command the app is ready for the Marketplace
17
- * Submit-app form: every dev/build run regenerates
18
- * `public/_anby/manifest.json`, which the marketplace shell fetches
19
- * directly. The publisher never edits any code by hand.
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.
20
11
  */
21
12
  export declare function initCommand(options: InitOptions): Promise<void>;
22
13
  export {};
@@ -1,31 +1,91 @@
1
- import { writeFile, readFile, 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://apps.anby.ai';
4
8
  /**
5
- * One-stop project bootstrap for an Anby app.
9
+ * `anby init` interactive scaffold + register.
6
10
  *
7
- * Run once after `npm create remix` (or any Vite-based stack):
8
- *
9
- * 1. Writes `anby-app.manifest.json` skeleton
10
- * 2. Patches `vite.config.ts` to load `anbyVitePlugin()` from
11
- * `@anby/platform-sdk/vite` (idempotent — skips if already wired)
12
- * 3. Adds `public/_anby/` to `.gitignore`
13
- *
14
- * After this single command the app is ready for the Marketplace
15
- * Submit-app form: every dev/build run regenerates
16
- * `public/_anby/manifest.json`, which the marketplace shell fetches
17
- * directly. The publisher never edits any code by hand.
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.
18
14
  */
19
15
  export async function initCommand(options) {
20
- await writeManifest(options);
21
- await patchViteConfig();
22
- await patchGitignore();
23
- const port = Number.parseInt(options.port ?? '3099', 10);
24
- console.log('');
25
- console.log(kleur.green(' Anby app bootstrap complete'));
26
- console.log(kleur.dim(` Next: npm run dev — then submit ${kleur.cyan(`http://localhost:${port}`)} via the Marketplace UI`));
27
- }
28
- async function writeManifest(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) {
29
89
  const target = resolve('anby-app.manifest.json');
30
90
  try {
31
91
  await access(target);
@@ -35,26 +95,23 @@ async function writeManifest(options) {
35
95
  catch {
36
96
  // ok — file doesn't exist
37
97
  }
38
- const id = options.id ?? 'com.example.my-app';
39
- const name = options.name ?? 'My App';
40
- const port = Number.parseInt(options.port ?? '3099', 10);
41
98
  const manifest = {
42
99
  $schema: 'https://anby.dev/schemas/app-manifest.v1.json',
43
- id,
100
+ id: opts.id,
44
101
  version: '1.0.0',
45
- name,
46
- description: `${name} — submitted via @anby/cli`,
102
+ name: opts.name,
103
+ description: `${opts.name} — submitted via @anby/cli`,
47
104
  icon: '📦',
48
105
  color: '#E63426',
49
106
  runtime: {
50
107
  type: 'remix',
51
- port,
108
+ port: opts.port,
52
109
  healthCheck: '/api/health',
53
110
  readyCheck: '/api/health',
54
111
  },
55
112
  frontend: {
56
113
  type: 'iframe',
57
- routes: [{ path: '/', label: name, icon: '📦' }],
114
+ routes: [{ path: '/', label: opts.name, icon: '📦' }],
58
115
  navPosition: 'sidebar',
59
116
  },
60
117
  provides: { entities: [], events: [] },
@@ -68,19 +125,9 @@ async function writeManifest(options) {
68
125
  database: { type: 'postgresql' },
69
126
  };
70
127
  await writeFile(target, JSON.stringify(manifest, null, 2) + '\n', 'utf-8');
71
- console.log(kleur.green(`✔ Wrote ${target}`));
128
+ console.log(kleur.green(`✔ Wrote anby-app.manifest.json`));
72
129
  }
73
- /**
74
- * Idempotently patch `vite.config.ts` (or `.js`/`.mts`/`.mjs`) to load
75
- * `anbyVitePlugin()`. The patch is a deliberately small textual edit:
76
- * we add the import line near the existing imports and inject
77
- * `anbyVitePlugin(),` as the first entry of the `plugins: [` array.
78
- *
79
- * If the file is too unusual to patch safely (no `plugins: [` literal),
80
- * we print a clear instruction for the publisher to add the lines by
81
- * hand. Either way the manifest skeleton has already been written, so
82
- * the command stays useful even when the patch fails.
83
- */
130
+ // ── Step 2: Vite config ───────────────────────────────────────────────
84
131
  async function patchViteConfig() {
85
132
  const candidates = [
86
133
  'vite.config.ts',
@@ -110,8 +157,6 @@ async function patchViteConfig() {
110
157
  return;
111
158
  }
112
159
  const importLine = "import { anbyVitePlugin } from '@anby/platform-sdk/vite';";
113
- // Insert the import after the last existing top-level `import ... from`
114
- // line so we don't accidentally split a multi-line import statement.
115
160
  const importRegex = /^import .+ from .+;?\s*$/gm;
116
161
  let lastImportEnd = -1;
117
162
  for (const match of original.matchAll(importRegex)) {
@@ -130,10 +175,6 @@ async function patchViteConfig() {
130
175
  else {
131
176
  withImport = importLine + '\n' + original;
132
177
  }
133
- // Inject `anbyVitePlugin(),` as the first item of the `plugins: [` array.
134
- // We match `plugins:` followed by `[` and any whitespace, and insert
135
- // right after the `[`. Idempotency is enforced by the earlier
136
- // `includes('anbyVitePlugin')` check above.
137
178
  const pluginsArrayRegex = /(plugins\s*:\s*\[)(\s*)/;
138
179
  if (!pluginsArrayRegex.test(withImport)) {
139
180
  console.log(kleur.yellow(`! Could not find a \`plugins: [...]\` array in ${target}. ` +
@@ -144,14 +185,9 @@ async function patchViteConfig() {
144
185
  await writeFile(path, patched, 'utf-8');
145
186
  console.log(kleur.green(`✔ Patched ${target} to load anbyVitePlugin`));
146
187
  }
147
- /**
148
- * Append `public/_anby/` to `.gitignore` so the auto-generated wire
149
- * manifest doesn't pollute commits. Idempotent — does nothing if the
150
- * line is already present, and creates the file if missing.
151
- */
188
+ // ── Step 3: .gitignore ────────────────────────────────────────────────
152
189
  async function patchGitignore() {
153
190
  const path = resolve('.gitignore');
154
- const line = 'public/_anby/';
155
191
  let existing = '';
156
192
  try {
157
193
  existing = await readFile(path, 'utf-8');
@@ -159,21 +195,447 @@ async function patchGitignore() {
159
195
  catch {
160
196
  // file doesn't exist — we'll create it below
161
197
  }
162
- // Match either `public/_anby/` or `public/_anby` on its own line, with
163
- // optional trailing slash and surrounding whitespace.
164
- const alreadyIgnored = existing
165
- .split(/\r?\n/)
166
- .map((l) => l.trim())
167
- .some((l) => l === line || l === 'public/_anby');
168
- if (alreadyIgnored) {
169
- console.log(kleur.dim('• .gitignore already covers public/_anby/ — no change'));
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'));
170
203
  return;
171
204
  }
172
- const block = (existing.length === 0 || existing.endsWith('\n') ? '' : '\n') +
173
- '\n# Anby — auto-generated wire manifest (do not commit)\n' +
174
- line +
175
- '\n';
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
+ }
176
215
  await writeFile(path, existing + block, 'utf-8');
177
- console.log(kleur.green('✔ Added public/_anby/ to .gitignore'));
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
+ // Also scaffold the manifest route so Marketplace Submit UI can
314
+ // fetch /_anby/manifest.json from the running app. Remix intercepts
315
+ // /_anby/* before Vite's public/ middleware, so we need an explicit
316
+ // route to serve the file from disk.
317
+ const manifestRouteTarget = resolve('app/routes/[_anby].manifest[.json].tsx');
318
+ try {
319
+ await access(manifestRouteTarget);
320
+ }
321
+ catch {
322
+ await writeFile(manifestRouteTarget, MANIFEST_ROUTE_TEMPLATE, 'utf-8');
323
+ console.log(kleur.green('✔ Scaffolded app/routes/[_anby].manifest[.json].tsx'));
324
+ }
325
+ // Scaffold /_anby/set-token route for auth token refresh via postMessage.
326
+ // Browsers block document.cookie in cross-origin iframes, so this
327
+ // endpoint lets the client-side auth handler set the cookie server-side.
328
+ const setTokenRouteTarget = resolve('app/routes/[_anby].set-token.tsx');
329
+ try {
330
+ await access(setTokenRouteTarget);
331
+ }
332
+ catch {
333
+ await writeFile(setTokenRouteTarget, SET_TOKEN_ROUTE_TEMPLATE, 'utf-8');
334
+ console.log(kleur.green('✔ Scaffolded app/routes/[_anby].set-token.tsx'));
335
+ }
336
+ }
337
+ const MANIFEST_ROUTE_TEMPLATE = `import { readFile } from 'node:fs/promises';
338
+ import { resolve } from 'node:path';
339
+
340
+ /**
341
+ * Serve public/_anby/manifest.json as a Remix route — auto-generated
342
+ * by \`anby init\`. Remix intercepts /_anby/* before Vite's public/
343
+ * middleware can serve the file, so we need an explicit route.
344
+ */
345
+ export async function loader() {
346
+ try {
347
+ const path = resolve(process.cwd(), 'public/_anby/manifest.json');
348
+ const raw = await readFile(path, 'utf-8');
349
+ return new Response(raw, {
350
+ headers: { 'Content-Type': 'application/json' },
351
+ });
352
+ } catch (err) {
353
+ return new Response(
354
+ JSON.stringify({ error: 'manifest not found', detail: (err as Error).message }),
355
+ { status: 404, headers: { 'Content-Type': 'application/json' } },
356
+ );
357
+ }
358
+ }
359
+ `;
360
+ const SET_TOKEN_ROUTE_TEMPLATE = `import type { ActionFunctionArgs } from '@remix-run/node';
361
+
362
+ /**
363
+ * POST /_anby/set-token — set auth-token cookie server-side.
364
+ * Auto-generated by \`anby init\`.
365
+ *
366
+ * Used by the platform auth postMessage handler to refresh the JWT
367
+ * cookie without relying on document.cookie (which browsers block in
368
+ * cross-origin iframes).
369
+ */
370
+ export async function action({ request }: ActionFunctionArgs) {
371
+ if (request.method !== 'POST') {
372
+ return new Response(null, { status: 405 });
373
+ }
374
+
375
+ const { token } = await request.json();
376
+ if (!token || typeof token !== 'string') {
377
+ return new Response(JSON.stringify({ error: 'missing token' }), {
378
+ status: 400,
379
+ headers: { 'Content-Type': 'application/json' },
380
+ });
381
+ }
382
+
383
+ return new Response(JSON.stringify({ ok: true }), {
384
+ status: 200,
385
+ headers: {
386
+ 'Content-Type': 'application/json',
387
+ 'Set-Cookie': \`auth-token=\${token}; Path=/; HttpOnly; SameSite=None; Secure; Max-Age=86400\`,
388
+ },
389
+ });
390
+ }
391
+ `;
392
+ // ── Step 5: Patch entry.server.tsx ────────────────────────────────────
393
+ async function patchEntryServer(port) {
394
+ const target = resolve('app/entry.server.tsx');
395
+ let original;
396
+ try {
397
+ original = await readFile(target, 'utf-8');
398
+ }
399
+ catch {
400
+ console.log(kleur.dim('• No app/entry.server.tsx found — skipping entry patch.'));
401
+ return;
402
+ }
403
+ if (original.includes('initAuth') && original.includes('_anby_token')) {
404
+ console.log(kleur.dim('• app/entry.server.tsx already has initAuth + token redirect — no patch needed'));
405
+ return;
406
+ }
407
+ if (original.includes('initAuth') && !original.includes('_anby_token')) {
408
+ // Patch only the _anby_token redirect into handleRequest
409
+ if (!original.includes('handleRequest')) {
410
+ console.log(kleur.dim('• app/entry.server.tsx has initAuth but no handleRequest — skipping token redirect patch'));
411
+ return;
412
+ }
413
+ // Insert token redirect at the start of handleRequest
414
+ const handleRequestBody = /handleRequest\s*\([^)]*\)\s*\{/;
415
+ const match = original.match(handleRequestBody);
416
+ if (match && match.index !== undefined) {
417
+ const insertPos = match.index + match[0].length;
418
+ const tokenRedirect = `
419
+ // When the platform shell embeds this app in an iframe, it passes the
420
+ // user's JWT via \`?_anby_token=...\`. Extract it, set a first-party
421
+ // cookie, and redirect to strip the token from the URL.
422
+ const url = new URL(request.url);
423
+ const anbyToken = url.searchParams.get('_anby_token');
424
+ if (anbyToken) {
425
+ url.searchParams.delete('_anby_token');
426
+ return new Response(null, {
427
+ status: 302,
428
+ headers: {
429
+ Location: url.pathname + url.search + url.hash,
430
+ 'Set-Cookie': \`auth-token=\${anbyToken}; Path=/; HttpOnly; SameSite=None; Secure; Max-Age=86400\`,
431
+ },
432
+ });
433
+ }
434
+ `;
435
+ const patched = original.slice(0, insertPos) + tokenRedirect + original.slice(insertPos);
436
+ await writeFile(target, patched, 'utf-8');
437
+ console.log(kleur.green('✔ Patched app/entry.server.tsx (_anby_token redirect)'));
438
+ }
439
+ else {
440
+ console.log(kleur.dim('• Could not locate handleRequest body — add _anby_token handling manually'));
441
+ }
442
+ return;
443
+ }
444
+ const sdkImport = "import { autoPublishOnBoot } from '@anby/platform-sdk';";
445
+ const authImport = "import { initAuth } from './lib/auth.server';";
446
+ const importRegex = /^import .+ from .+;?\s*$/gm;
447
+ let lastImportEnd = -1;
448
+ for (const match of original.matchAll(importRegex)) {
449
+ if (match.index !== undefined) {
450
+ lastImportEnd = match.index + match[0].length;
451
+ }
452
+ }
453
+ let withImports;
454
+ if (lastImportEnd >= 0) {
455
+ withImports =
456
+ original.slice(0, lastImportEnd) +
457
+ '\n' +
458
+ sdkImport +
459
+ '\n' +
460
+ authImport +
461
+ original.slice(lastImportEnd);
462
+ }
463
+ else {
464
+ withImports = sdkImport + '\n' + authImport + '\n' + original;
465
+ }
466
+ const bootstrapBlock = `
467
+ // Anby platform bootstrap — auto-generated by \`anby init\`.
468
+ // Ensures auth + discovery are ready before the first request.
469
+ await initAuth();
470
+ autoPublishOnBoot({
471
+ publicUrl: process.env.APP_PUBLIC_URL || \`http://localhost:\${process.env.PORT || ${port}}\`,
472
+ });
473
+ `;
474
+ const exportRegex = /^export\s+(default|function|async\s+function)/m;
475
+ const exportMatch = withImports.match(exportRegex);
476
+ let patched;
477
+ if (exportMatch && exportMatch.index !== undefined) {
478
+ patched =
479
+ withImports.slice(0, exportMatch.index) +
480
+ bootstrapBlock +
481
+ '\n' +
482
+ withImports.slice(exportMatch.index);
483
+ }
484
+ else {
485
+ patched = withImports + '\n' + bootstrapBlock;
486
+ }
487
+ // Also add _anby_token redirect in handleRequest
488
+ const handleRequestBody = /handleRequest\s*\([^)]*\)\s*\{/;
489
+ const hrMatch = patched.match(handleRequestBody);
490
+ if (hrMatch && hrMatch.index !== undefined) {
491
+ const insertPos = hrMatch.index + hrMatch[0].length;
492
+ const tokenRedirect = `
493
+ // When the platform shell embeds this app in an iframe, it passes the
494
+ // user's JWT via \`?_anby_token=...\`. Extract it, set a first-party
495
+ // cookie, and redirect to strip the token from the URL.
496
+ const url = new URL(request.url);
497
+ const anbyToken = url.searchParams.get('_anby_token');
498
+ if (anbyToken) {
499
+ url.searchParams.delete('_anby_token');
500
+ return new Response(null, {
501
+ status: 302,
502
+ headers: {
503
+ Location: url.pathname + url.search + url.hash,
504
+ 'Set-Cookie': \`auth-token=\${anbyToken}; Path=/; HttpOnly; SameSite=None; Secure; Max-Age=86400\`,
505
+ },
506
+ });
507
+ }
508
+ `;
509
+ patched = patched.slice(0, insertPos) + tokenRedirect + patched.slice(insertPos);
510
+ }
511
+ await writeFile(target, patched, 'utf-8');
512
+ console.log(kleur.green('✔ Patched app/entry.server.tsx (initAuth + autoPublishOnBoot + token redirect)'));
513
+ }
514
+ // ── Step 6: Self-register with registry ───────────────────────────────
515
+ async function registerAndWriteToken(opts) {
516
+ if (!opts.auth) {
517
+ console.log(kleur.yellow('! Not logged in — run `anby login` first, then `anby init` again'));
518
+ return;
519
+ }
520
+ // Check if .env already has a valid ANBY_APP_TOKEN for THIS registry
521
+ const envPath = resolve('.env');
522
+ try {
523
+ const envContent = await readFile(envPath, 'utf-8');
524
+ const match = envContent.match(/^ANBY_APP_TOKEN=(.*)$/m);
525
+ if (match && match[1].trim()) {
526
+ // Decode token to check platformUrl
527
+ try {
528
+ const b64 = match[1].trim().replace('anby_v1_', '');
529
+ const payload = JSON.parse(Buffer.from(b64, 'base64url').toString());
530
+ const tokenPlatform = (payload.platformUrl || '').replace(/\/+$/, '');
531
+ const targetPlatform = opts.registryBase.replace(/\/+$/, '');
532
+ if (tokenPlatform === targetPlatform) {
533
+ console.log(kleur.dim('• .env already contains ANBY_APP_TOKEN for this registry — skipping registration'));
534
+ return;
535
+ }
536
+ console.log(kleur.dim(`• Token in .env points to ${tokenPlatform}, re-registering for ${targetPlatform}`));
537
+ }
538
+ catch {
539
+ // Can't parse — re-register
540
+ }
541
+ }
542
+ }
543
+ catch {
544
+ // .env doesn't exist — fine, we'll create it
545
+ }
546
+ // Load the manifest we just wrote
547
+ let manifest;
548
+ try {
549
+ const raw = await readFile(resolve('anby-app.manifest.json'), 'utf-8');
550
+ manifest = JSON.parse(raw);
551
+ }
552
+ catch {
553
+ console.log(kleur.yellow('! Could not read anby-app.manifest.json — skipping registration'));
554
+ return;
555
+ }
556
+ const publicUrl = `http://localhost:${opts.port}`;
557
+ const registryUrl = `${opts.registryBase}/registry/apps`;
558
+ // Register with a minimal manifest (just metadata, no entities).
559
+ // Entity declarations are published later by autoPublishOnBoot when
560
+ // the developer runs `npm run dev` — by then they've had time to
561
+ // edit the manifest with the correct provides/requires.
562
+ const registrationManifest = {
563
+ ...manifest,
564
+ provides: { entities: [], events: [] },
565
+ requires: { ...manifest.requires, entities: [], events: [] },
566
+ };
567
+ const body = {
568
+ id: manifest.id,
569
+ name: manifest.name,
570
+ description: manifest.description,
571
+ icon: manifest.icon,
572
+ color: manifest.color,
573
+ publisherId: manifest.id.split('.').slice(0, 2).join('.'),
574
+ version: manifest.version,
575
+ publicUrl,
576
+ submittedBy: `cli:${opts.auth.email}`,
577
+ manifest: registrationManifest,
578
+ };
579
+ let res;
580
+ try {
581
+ res = await fetch(registryUrl, {
582
+ method: 'POST',
583
+ headers: {
584
+ 'Content-Type': 'application/json',
585
+ Authorization: `Bearer ${opts.auth.token}`,
586
+ },
587
+ body: JSON.stringify(body),
588
+ signal: AbortSignal.timeout(10_000),
589
+ });
590
+ }
591
+ catch (err) {
592
+ console.log(kleur.yellow(`! Could not reach registry at ${registryUrl}: ${err.message}`));
593
+ return;
594
+ }
595
+ if (!res.ok) {
596
+ const errBody = await res.text();
597
+ console.log(kleur.yellow(`! Registry rejected publish (${res.status}): ${errBody}`));
598
+ return;
599
+ }
600
+ const result = await res.json();
601
+ if (!result.privateKey) {
602
+ console.log(kleur.dim('• App already registered (no new private key). Run `anby app rotate-token` for a new token.'));
603
+ return;
604
+ }
605
+ // Assemble token — platformUrl is the registry base (used by SDK discovery)
606
+ const token = assembleToken({
607
+ appId: manifest.id,
608
+ platformUrl: opts.registryBase,
609
+ privateKey: result.privateKey,
610
+ });
611
+ // Upsert into .env: replace existing ANBY_APP_TOKEN/APP_PUBLIC_URL
612
+ // lines if present, otherwise append.
613
+ let envContent = '';
614
+ try {
615
+ envContent = await readFile(envPath, 'utf-8');
616
+ }
617
+ catch {
618
+ // File doesn't exist — start fresh
619
+ }
620
+ envContent = upsertEnvVar(envContent, 'ANBY_APP_TOKEN', token);
621
+ envContent = upsertEnvVar(envContent, 'APP_PUBLIC_URL', `http://localhost:${opts.port}`);
622
+ await writeFile(envPath, envContent, { mode: 0o600 });
623
+ console.log(kleur.green('✔ Registered app with registry'));
624
+ console.log(kleur.green('✔ Wrote ANBY_APP_TOKEN to .env'));
625
+ }
626
+ /**
627
+ * Upsert an env var into a .env file content string.
628
+ * If the key exists (with or without value), replace the line.
629
+ * Otherwise append to the end.
630
+ */
631
+ function upsertEnvVar(content, key, value) {
632
+ const line = `${key}=${value}`;
633
+ const regex = new RegExp(`^${key}=.*$`, 'm');
634
+ if (regex.test(content)) {
635
+ return content.replace(regex, line);
636
+ }
637
+ // Append, ensuring file ends with newline
638
+ const sep = content.length === 0 || content.endsWith('\n') ? '' : '\n';
639
+ return content + sep + line + '\n';
178
640
  }
179
641
  //# sourceMappingURL=init.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACtE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACrE,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAEhD,MAAM,oBAAoB,GAAG,sBAAsB,CAAC;AAOpD;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,OAAoB;IACpD,MAAM,EAAE,GAAG,eAAe,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IAE7E,IAAI,CAAC;QACH,mEAAmE;QACnE,MAAM,IAAI,GAAG,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QAClE,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,wBAAwB,CAAC,CAAC,CAAC;YACjD,OAAO;QACT,CAAC;QAED,MAAM,SAAS,GAAG,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QAClF,MAAM,IAAI,GAAG,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QAC/D,IAAI,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;YACvB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC,CAAC;YACzC,OAAO;QACT,CAAC;QAED,mEAAmE;QACnE,MAAM,IAAI,GAAG,MAAM,aAAa,EAAE,CAAC;QACnC,MAAM,WAAW,GAAG,IAAI,CAAC,CAAC,CAAC,cAAc,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC;QAEtE,kCAAkC;QAClC,MAAM,aAAa,GAAG,WAAW,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACjE,8CAA8C;QAC9C,MAAM,IAAI,GAAG,IAAI;aACd,WAAW,EAAE;aACb,OAAO,CAAC,aAAa,EAAE,GAAG,CAAC;aAC3B,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;QAEzB,IAAI,EAAE,GAAG,GAAG,aAAa,IAAI,IAAI,EAAE,CAAC;QAEpC,8DAA8D;QAC9D,MAAM,YAAY,GAAG,CACnB,OAAO,CAAC,WAAW;YACnB,OAAO,CAAC,GAAG,CAAC,iBAAiB;YAC7B,oBAAoB,CACrB,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QAEtB,MAAM,UAAU,GAAG,MAAM,cAAc,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC;QAC1D,IAAI,UAAU,EAAE,CAAC;YACf,+BAA+B;YAC/B,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;YACtD,EAAE,GAAG,GAAG,aAAa,IAAI,IAAI,IAAI,MAAM,EAAE,CAAC;YAC1C,OAAO,CAAC,GAAG,CACT,KAAK,CAAC,GAAG,CAAC,aAAa,aAAa,IAAI,IAAI,2BAA2B,EAAE,EAAE,CAAC,CAC7E,CAAC;QACJ,CAAC;QAED,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,aAAa,EAAE,EAAE,CAAC,CAAC,CAAC;QAC1C,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAEhB,mEAAmE;QACnE,MAAM,aAAa,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;QACxC,MAAM,eAAe,EAAE,CAAC;QACxB,MAAM,cAAc,EAAE,CAAC;QACvB,MAAM,kBAAkB,EAAE,CAAC;QAC3B,MAAM,gBAAgB,CAAC,IAAI,CAAC,CAAC;QAC7B,MAAM,qBAAqB,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,CAAC;QAEpE,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAChB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,+BAA+B,CAAC,CAAC,CAAC;QAC1D,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAChB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC;QACvC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,aAAa,KAAK,CAAC,IAAI,CAAC,wBAAwB,CAAC,+BAA+B,CAAC,CAAC,CAAC;QACzG,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,kEAAkE,CAAC,CAAC,CAAC;QAC3F,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,KAAK,CAAC,IAAI,CAAC,aAAa,CAAC,oDAAoD,CAAC,CAAC,CAAC;QAC9G,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,sCAAsC,KAAK,CAAC,IAAI,CAAC,oBAAoB,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;IACzG,CAAC;YAAS,CAAC;QACT,EAAE,CAAC,KAAK,EAAE,CAAC;IACb,CAAC;AACH,CAAC;AAED,2EAA2E;AAE3E,KAAK,UAAU,cAAc,CAAC,YAAoB,EAAE,KAAa;IAC/D,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,YAAY,kBAAkB,KAAK,WAAW,EAAE;YACzE,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC;SAClC,CAAC,CAAC;QACH,OAAO,GAAG,CAAC,EAAE,CAAC;IAChB,CAAC;IAAC,MAAM,CAAC;QACP,0CAA0C;QAC1C,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,yEAAyE;AAEzE,KAAK,UAAU,aAAa,CAAC,IAI5B;IACC,MAAM,MAAM,GAAG,OAAO,CAAC,wBAAwB,CAAC,CAAC;IAEjD,IAAI,CAAC;QACH,MAAM,MAAM,CAAC,MAAM,CAAC,CAAC;QACrB,OAAO,CAAC,GAAG,CACT,KAAK,CAAC,GAAG,CAAC,KAAK,MAAM,oCAAoC,CAAC,CAC3D,CAAC;QACF,OAAO;IACT,CAAC;IAAC,MAAM,CAAC;QACP,0BAA0B;IAC5B,CAAC;IAED,MAAM,QAAQ,GAAG;QACf,OAAO,EAAE,+CAA+C;QACxD,EAAE,EAAE,IAAI,CAAC,EAAE;QACX,OAAO,EAAE,OAAO;QAChB,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,WAAW,EAAE,GAAG,IAAI,CAAC,IAAI,4BAA4B;QACrD,IAAI,EAAE,IAAI;QACV,KAAK,EAAE,SAAS;QAChB,OAAO,EAAE;YACP,IAAI,EAAE,OAAO;YACb,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,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,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;YACrD,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,gCAAgC,CAAC,CAAC,CAAC;AAC7D,CAAC;AAED,yEAAyE;AAEzE,KAAK,UAAU,eAAe;IAC5B,MAAM,UAAU,GAAG;QACjB,gBAAgB;QAChB,iBAAiB;QACjB,gBAAgB;QAChB,iBAAiB;KAClB,CAAC;IACF,IAAI,MAAM,GAAkB,IAAI,CAAC;IACjC,KAAK,MAAM,IAAI,IAAI,UAAU,EAAE,CAAC;QAC9B,IAAI,CAAC;YACH,MAAM,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;YAC5B,MAAM,GAAG,IAAI,CAAC;YACd,MAAM;QACR,CAAC;QAAC,MAAM,CAAC;YACP,WAAW;QACb,CAAC;IACH,CAAC;IACD,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO,CAAC,GAAG,CACT,KAAK,CAAC,GAAG,CACP,oIAAoI,CACrI,CACF,CAAC;QACF,OAAO;IACT,CAAC;IAED,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC7B,MAAM,QAAQ,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IAE/C,IAAI,QAAQ,CAAC,QAAQ,CAAC,gBAAgB,CAAC,EAAE,CAAC;QACxC,OAAO,CAAC,GAAG,CACT,KAAK,CAAC,GAAG,CAAC,KAAK,MAAM,iDAAiD,CAAC,CACxE,CAAC;QACF,OAAO;IACT,CAAC;IAED,MAAM,UAAU,GACd,2DAA2D,CAAC;IAE9D,MAAM,WAAW,GAAG,4BAA4B,CAAC;IACjD,IAAI,aAAa,GAAG,CAAC,CAAC,CAAC;IACvB,KAAK,MAAM,KAAK,IAAI,QAAQ,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC;QACnD,IAAI,KAAK,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;YAC9B,aAAa,GAAG,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;QAChD,CAAC;IACH,CAAC;IAED,IAAI,UAAkB,CAAC;IACvB,IAAI,aAAa,IAAI,CAAC,EAAE,CAAC;QACvB,UAAU;YACR,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,aAAa,CAAC;gBAChC,IAAI;gBACJ,UAAU;gBACV,QAAQ,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC;IAClC,CAAC;SAAM,CAAC;QACN,UAAU,GAAG,UAAU,GAAG,IAAI,GAAG,QAAQ,CAAC;IAC5C,CAAC;IAED,MAAM,iBAAiB,GAAG,yBAAyB,CAAC;IACpD,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC;QACxC,OAAO,CAAC,GAAG,CACT,KAAK,CAAC,MAAM,CACV,kDAAkD,MAAM,IAAI;YAC1D,OAAO,KAAK,CAAC,IAAI,CAAC,kBAAkB,CAAC,4BAA4B,CACpE,CACF,CAAC;QACF,OAAO;IACT,CAAC;IAED,MAAM,OAAO,GAAG,UAAU,CAAC,OAAO,CAChC,iBAAiB,EACjB,CAAC,CAAC,EAAE,IAAY,EAAE,EAAU,EAAE,EAAE,CAAC,GAAG,IAAI,GAAG,EAAE,oBAAoB,EAAE,EAAE,CACtE,CAAC;IAEF,MAAM,SAAS,CAAC,IAAI,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;IACxC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,aAAa,MAAM,yBAAyB,CAAC,CAAC,CAAC;AACzE,CAAC;AAED,yEAAyE;AAEzE,KAAK,UAAU,cAAc;IAC3B,MAAM,IAAI,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;IACnC,IAAI,QAAQ,GAAG,EAAE,CAAC;IAClB,IAAI,CAAC;QACH,QAAQ,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IAC3C,CAAC;IAAC,MAAM,CAAC;QACP,6CAA6C;IAC/C,CAAC;IAED,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;IAC3D,MAAM,eAAe,GAAG,CAAC,KAAK,CAAC,IAAI,CACjC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,eAAe,IAAI,CAAC,KAAK,cAAc,CACrD,CAAC;IACF,MAAM,YAAY,GAAG,CAAC,KAAK,CAAC,IAAI,CAC9B,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,QAAQ,IAAI,CAAC,KAAK,OAAO,CACvC,CAAC;IAEF,IAAI,CAAC,eAAe,IAAI,CAAC,YAAY,EAAE,CAAC;QACtC,OAAO,CAAC,GAAG,CACT,KAAK,CAAC,GAAG,CAAC,oDAAoD,CAAC,CAChE,CAAC;QACF,OAAO;IACT,CAAC;IAED,IAAI,KAAK,GAAG,EAAE,CAAC;IACf,IAAI,eAAe,IAAI,YAAY,EAAE,CAAC;QACpC,KAAK;YACH,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC,IAAI,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;gBAC9D,mDAAmD,CAAC;QACtD,IAAI,eAAe;YAAE,KAAK,IAAI,iBAAiB,CAAC;QAChD,IAAI,YAAY;YAAE,KAAK,IAAI,UAAU,CAAC;IACxC,CAAC;IAED,MAAM,SAAS,CAAC,IAAI,EAAE,QAAQ,GAAG,KAAK,EAAE,OAAO,CAAC,CAAC;IACjD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,qCAAqC,CAAC,CAAC,CAAC;AAClE,CAAC;AAED,yEAAyE;AAEzE,MAAM,oBAAoB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAuE5B,CAAC;AAEF,KAAK,UAAU,kBAAkB;IAC/B,MAAM,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC;IAC9B,IAAI,CAAC;QACH,MAAM,MAAM,CAAC,MAAM,CAAC,CAAC;IACvB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,CAAC,GAAG,CACT,KAAK,CAAC,GAAG,CACP,qFAAqF,CACtF,CACF,CAAC;QACF,OAAO;IACT,CAAC;IAED,MAAM,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC;IAClC,MAAM,MAAM,GAAG,OAAO,CAAC,wBAAwB,CAAC,CAAC;IAEjD,IAAI,CAAC;QACH,MAAM,MAAM,CAAC,MAAM,CAAC,CAAC;QACrB,OAAO,CAAC,GAAG,CACT,KAAK,CAAC,GAAG,CAAC,4DAA4D,CAAC,CACxE,CAAC;QACF,OAAO;IACT,CAAC;IAAC,MAAM,CAAC;QACP,2CAA2C;IAC7C,CAAC;IAED,MAAM,KAAK,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACzC,MAAM,SAAS,CAAC,MAAM,EAAE,oBAAoB,EAAE,OAAO,CAAC,CAAC;IACvD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,qCAAqC,CAAC,CAAC,CAAC;IAEhE,gEAAgE;IAChE,oEAAoE;IACpE,oEAAoE;IACpE,qCAAqC;IACrC,MAAM,mBAAmB,GAAG,OAAO,CAAC,wCAAwC,CAAC,CAAC;IAC9E,IAAI,CAAC;QACH,MAAM,MAAM,CAAC,mBAAmB,CAAC,CAAC;IACpC,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,SAAS,CAAC,mBAAmB,EAAE,uBAAuB,EAAE,OAAO,CAAC,CAAC;QACvE,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,qDAAqD,CAAC,CAAC,CAAC;IAClF,CAAC;IAED,0EAA0E;IAC1E,kEAAkE;IAClE,yEAAyE;IACzE,MAAM,mBAAmB,GAAG,OAAO,CAAC,kCAAkC,CAAC,CAAC;IACxE,IAAI,CAAC;QACH,MAAM,MAAM,CAAC,mBAAmB,CAAC,CAAC;IACpC,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,SAAS,CAAC,mBAAmB,EAAE,wBAAwB,EAAE,OAAO,CAAC,CAAC;QACxE,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,+CAA+C,CAAC,CAAC,CAAC;IAC5E,CAAC;AACH,CAAC;AAED,MAAM,uBAAuB,GAAG;;;;;;;;;;;;;;;;;;;;;;CAsB/B,CAAC;AAEF,MAAM,wBAAwB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+BhC,CAAC;AAEF,yEAAyE;AAEzE,KAAK,UAAU,gBAAgB,CAAC,IAAY;IAC1C,MAAM,MAAM,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAAC;IAC/C,IAAI,QAAgB,CAAC;IACrB,IAAI,CAAC;QACH,QAAQ,GAAG,MAAM,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC7C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,CAAC,GAAG,CACT,KAAK,CAAC,GAAG,CACP,yDAAyD,CAC1D,CACF,CAAC;QACF,OAAO;IACT,CAAC;IAED,IAAI,QAAQ,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,QAAQ,CAAC,QAAQ,CAAC,aAAa,CAAC,EAAE,CAAC;QACtE,OAAO,CAAC,GAAG,CACT,KAAK,CAAC,GAAG,CAAC,gFAAgF,CAAC,CAC5F,CAAC;QACF,OAAO;IACT,CAAC;IAED,IAAI,QAAQ,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,aAAa,CAAC,EAAE,CAAC;QACvE,yDAAyD;QACzD,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,eAAe,CAAC,EAAE,CAAC;YACxC,OAAO,CAAC,GAAG,CACT,KAAK,CAAC,GAAG,CAAC,0FAA0F,CAAC,CACtG,CAAC;YACF,OAAO;QACT,CAAC;QACD,sDAAsD;QACtD,MAAM,iBAAiB,GAAG,gCAAgC,CAAC;QAC3D,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAC;QAChD,IAAI,KAAK,IAAI,KAAK,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;YACvC,MAAM,SAAS,GAAG,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;YAChD,MAAM,aAAa,GAAG;;;;;;;;;;;;;;;;CAgB3B,CAAC;YACI,MAAM,OAAO,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,SAAS,CAAC,GAAG,aAAa,GAAG,QAAQ,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;YACzF,MAAM,SAAS,CAAC,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;YAC1C,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,uDAAuD,CAAC,CAAC,CAAC;QACpF,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,GAAG,CACT,KAAK,CAAC,GAAG,CAAC,2EAA2E,CAAC,CACvF,CAAC;QACJ,CAAC;QACD,OAAO;IACT,CAAC;IAED,MAAM,SAAS,GAAG,yDAAyD,CAAC;IAC5E,MAAM,UAAU,GAAG,+CAA+C,CAAC;IAEnE,MAAM,WAAW,GAAG,4BAA4B,CAAC;IACjD,IAAI,aAAa,GAAG,CAAC,CAAC,CAAC;IACvB,KAAK,MAAM,KAAK,IAAI,QAAQ,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC;QACnD,IAAI,KAAK,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;YAC9B,aAAa,GAAG,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;QAChD,CAAC;IACH,CAAC;IAED,IAAI,WAAmB,CAAC;IACxB,IAAI,aAAa,IAAI,CAAC,EAAE,CAAC;QACvB,WAAW;YACT,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,aAAa,CAAC;gBAChC,IAAI;gBACJ,SAAS;gBACT,IAAI;gBACJ,UAAU;gBACV,QAAQ,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC;IAClC,CAAC;SAAM,CAAC;QACN,WAAW,GAAG,SAAS,GAAG,IAAI,GAAG,UAAU,GAAG,IAAI,GAAG,QAAQ,CAAC;IAChE,CAAC;IAED,MAAM,cAAc,GAAG;;;;;uFAK8D,IAAI;;CAE1F,CAAC;IAEA,MAAM,WAAW,GAAG,gDAAgD,CAAC;IACrE,MAAM,WAAW,GAAG,WAAW,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;IACnD,IAAI,OAAe,CAAC;IACpB,IAAI,WAAW,IAAI,WAAW,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;QACnD,OAAO;YACL,WAAW,CAAC,KAAK,CAAC,CAAC,EAAE,WAAW,CAAC,KAAK,CAAC;gBACvC,cAAc;gBACd,IAAI;gBACJ,WAAW,CAAC,KAAK,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;IACzC,CAAC;SAAM,CAAC;QACN,OAAO,GAAG,WAAW,GAAG,IAAI,GAAG,cAAc,CAAC;IAChD,CAAC;IAED,iDAAiD;IACjD,MAAM,iBAAiB,GAAG,gCAAgC,CAAC;IAC3D,MAAM,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAC;IACjD,IAAI,OAAO,IAAI,OAAO,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;QAC3C,MAAM,SAAS,GAAG,OAAO,CAAC,KAAK,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;QACpD,MAAM,aAAa,GAAG;;;;;;;;;;;;;;;;CAgBzB,CAAC;QACE,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,SAAS,CAAC,GAAG,aAAa,GAAG,OAAO,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;IACnF,CAAC;IAED,MAAM,SAAS,CAAC,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;IAC1C,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,gFAAgF,CAAC,CAAC,CAAC;AAC7G,CAAC;AAED,yEAAyE;AAEzE,KAAK,UAAU,qBAAqB,CAAC,IAMpC;IACC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;QACf,OAAO,CAAC,GAAG,CACT,KAAK,CAAC,MAAM,CACV,kEAAkE,CACnE,CACF,CAAC;QACF,OAAO;IACT,CAAC;IAED,qEAAqE;IACrE,MAAM,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAChC,IAAI,CAAC;QACH,MAAM,UAAU,GAAG,MAAM,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACpD,MAAM,KAAK,GAAG,UAAU,CAAC,KAAK,CAAC,wBAAwB,CAAC,CAAC;QACzD,IAAI,KAAK,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC;YAC7B,oCAAoC;YACpC,IAAI,CAAC;gBACH,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;gBACpD,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;gBACrE,MAAM,aAAa,GAAG,CAAC,OAAO,CAAC,WAAW,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;gBACtE,MAAM,cAAc,GAAG,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;gBAC7D,IAAI,aAAa,KAAK,cAAc,EAAE,CAAC;oBACrC,OAAO,CAAC,GAAG,CACT,KAAK,CAAC,GAAG,CAAC,kFAAkF,CAAC,CAC9F,CAAC;oBACF,OAAO;gBACT,CAAC;gBACD,OAAO,CAAC,GAAG,CACT,KAAK,CAAC,GAAG,CAAC,6BAA6B,aAAa,wBAAwB,cAAc,EAAE,CAAC,CAC9F,CAAC;YACJ,CAAC;YAAC,MAAM,CAAC;gBACP,4BAA4B;YAC9B,CAAC;QACH,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,6CAA6C;IAC/C,CAAC;IAED,kCAAkC;IAClC,IAAI,QAAQ,CAAC;IACb,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,OAAO,CAAC,wBAAwB,CAAC,EAAE,OAAO,CAAC,CAAC;QACvE,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC7B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,CAAC,GAAG,CACT,KAAK,CAAC,MAAM,CAAC,iEAAiE,CAAC,CAChF,CAAC;QACF,OAAO;IACT,CAAC;IAED,MAAM,SAAS,GAAG,oBAAoB,IAAI,CAAC,IAAI,EAAE,CAAC;IAClD,MAAM,WAAW,GAAG,GAAG,IAAI,CAAC,YAAY,gBAAgB,CAAC;IAEzD,iEAAiE;IACjE,oEAAoE;IACpE,iEAAiE;IACjE,wDAAwD;IACxD,MAAM,oBAAoB,GAAG;QAC3B,GAAG,QAAQ;QACX,QAAQ,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE;QACtC,QAAQ,EAAE,EAAE,GAAG,QAAQ,CAAC,QAAQ,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE;KAC7D,CAAC;IAEF,MAAM,IAAI,GAAG;QACX,EAAE,EAAE,QAAQ,CAAC,EAAE;QACf,IAAI,EAAE,QAAQ,CAAC,IAAI;QACnB,WAAW,EAAE,QAAQ,CAAC,WAAW;QACjC,IAAI,EAAE,QAAQ,CAAC,IAAI;QACnB,KAAK,EAAE,QAAQ,CAAC,KAAK;QACrB,WAAW,EAAE,QAAQ,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC;QACzD,OAAO,EAAE,QAAQ,CAAC,OAAO;QACzB,SAAS;QACT,WAAW,EAAE,OAAO,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE;QACrC,QAAQ,EAAE,oBAAoB;KAC/B,CAAC;IAEF,IAAI,GAAa,CAAC;IAClB,IAAI,CAAC;QACH,GAAG,GAAG,MAAM,KAAK,CAAC,WAAW,EAAE;YAC7B,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACP,cAAc,EAAE,kBAAkB;gBAClC,aAAa,EAAE,UAAU,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE;aAC3C;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;YAC1B,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,MAAM,CAAC;SACpC,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,GAAG,CACT,KAAK,CAAC,MAAM,CACV,iCAAiC,WAAW,KAAM,GAAa,CAAC,OAAO,EAAE,CAC1E,CACF,CAAC;QACF,OAAO;IACT,CAAC;IAED,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;QACZ,MAAM,OAAO,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;QACjC,OAAO,CAAC,GAAG,CACT,KAAK,CAAC,MAAM,CAAC,gCAAgC,GAAG,CAAC,MAAM,MAAM,OAAO,EAAE,CAAC,CACxE,CAAC;QACF,OAAO;IACT,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;IAEhC,IAAI,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC;QACvB,OAAO,CAAC,GAAG,CACT,KAAK,CAAC,GAAG,CACP,6FAA6F,CAC9F,CACF,CAAC;QACF,OAAO;IACT,CAAC;IAED,4EAA4E;IAC5E,MAAM,KAAK,GAAG,aAAa,CAAC;QAC1B,KAAK,EAAE,QAAQ,CAAC,EAAE;QAClB,WAAW,EAAE,IAAI,CAAC,YAAY;QAC9B,UAAU,EAAE,MAAM,CAAC,UAAU;KAC9B,CAAC,CAAC;IAEH,mEAAmE;IACnE,sCAAsC;IACtC,IAAI,UAAU,GAAG,EAAE,CAAC;IACpB,IAAI,CAAC;QACH,UAAU,GAAG,MAAM,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IAChD,CAAC;IAAC,MAAM,CAAC;QACP,mCAAmC;IACrC,CAAC;IAED,UAAU,GAAG,YAAY,CAAC,UAAU,EAAE,gBAAgB,EAAE,KAAK,CAAC,CAAC;IAC/D,UAAU,GAAG,YAAY,CACvB,UAAU,EACV,gBAAgB,EAChB,oBAAoB,IAAI,CAAC,IAAI,EAAE,CAChC,CAAC;IAEF,MAAM,SAAS,CAAC,OAAO,EAAE,UAAU,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IACtD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,gCAAgC,CAAC,CAAC,CAAC;IAC3D,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,gCAAgC,CAAC,CAAC,CAAC;AAC7D,CAAC;AAED;;;;GAIG;AACH,SAAS,YAAY,CAAC,OAAe,EAAE,GAAW,EAAE,KAAa;IAC/D,MAAM,IAAI,GAAG,GAAG,GAAG,IAAI,KAAK,EAAE,CAAC;IAC/B,MAAM,KAAK,GAAG,IAAI,MAAM,CAAC,IAAI,GAAG,MAAM,EAAE,GAAG,CAAC,CAAC;IAC7C,IAAI,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;QACxB,OAAO,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;IACtC,CAAC;IACD,0CAA0C;IAC1C,MAAM,GAAG,GAAG,OAAO,CAAC,MAAM,KAAK,CAAC,IAAI,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;IACvE,OAAO,OAAO,GAAG,GAAG,GAAG,IAAI,GAAG,IAAI,CAAC;AACrC,CAAC"}
@@ -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"}
@@ -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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@anby/cli",
3
- "version": "0.7.0",
3
+ "version": "0.9.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.7.0",
46
+ "@anby/platform-sdk": "^0.9.0",
47
47
  "commander": "^12.1.0",
48
48
  "kleur": "^4.1.5"
49
49
  },