@youcan/app 2.3.0 → 2.3.2

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.
@@ -1,7 +1,8 @@
1
- import { Session, Tasks, UI, System, Services, Env, Http } from '@youcan/cli-kit';
2
1
  import { bootTunnelWorker, bootAppWorker, bootWebWorker, bootExtensionWorker } from '../../services/dev/workers/index.js';
2
+ import { APP_CONFIG_FILENAME } from '../../../constants.js';
3
3
  import { AppCommand } from '../../../util/app-command.js';
4
4
  import { load } from '../../../util/app-loader.js';
5
+ import { Session, Tasks, UI, System, Services, Filesystem, Path, Env, Http } from '@youcan/cli-kit';
5
6
 
6
7
  class Dev extends AppCommand {
7
8
  static description = 'Run the app in dev mode';
@@ -43,18 +44,27 @@ class Dev extends AppCommand {
43
44
  }
44
45
  async prepareNetworkOptions() {
45
46
  const port = await System.getNextAvailablePort(3000);
46
- // Start by `localhost` until a tunneled url is available
47
- const appUrl = `http://localhost:${port}`;
48
- this.app.networkConfig = { port, appUrl };
47
+ this.app.network_config = {
48
+ app_port: port,
49
+ app_url: `http://localhost:${port}`,
50
+ };
49
51
  const worker = await bootTunnelWorker(this, this.app, new Services.Cloudflared());
52
+ this.app.config = {
53
+ ...this.app.config,
54
+ app_url: worker.getUrl(),
55
+ redirect_urls: this.app.config.redirect_urls?.length > 0
56
+ ? this.app.config.redirect_urls.map(r => new URL(new URL(r).pathname, worker.getUrl()).toString())
57
+ : [new URL('/auth/callback', worker.getUrl()).toString()],
58
+ };
59
+ await Filesystem.writeJsonFile(Path.join(this.app.root, APP_CONFIG_FILENAME), this.app.config);
50
60
  return worker;
51
61
  }
52
62
  async reloadWorkers() {
53
63
  this.controller = new AbortController();
54
64
  // Preserve network config.
55
- const networkConfig = this.app.networkConfig;
65
+ const networkConfig = this.app.network_config;
56
66
  this.app = await load();
57
- this.app.networkConfig = networkConfig;
67
+ this.app.network_config = networkConfig;
58
68
  await this.syncAppConfig();
59
69
  await this.runWorkers(await this.prepareDevProcesses());
60
70
  }
@@ -70,18 +80,18 @@ class Dev extends AppCommand {
70
80
  return Promise.all(promises);
71
81
  }
72
82
  buildEnvironmentVariables() {
73
- if (!this.app.remoteConfig) {
83
+ if (!this.app.remote_config) {
74
84
  throw new Error('remote app config not loaded');
75
85
  }
76
- if (!this.app.networkConfig) {
86
+ if (!this.app.network_config) {
77
87
  throw new Error('app network config is not set');
78
88
  }
79
89
  return {
80
- YOUCAN_API_KEY: this.app.remoteConfig.client_id,
81
- YOUCAN_API_SECRET: this.app.remoteConfig.client_secret,
82
- YOUCAN_API_SCOPES: this.app.remoteConfig.scopes.join(','),
83
- APP_URL: this.app.networkConfig.appUrl,
84
- PORT: this.app.networkConfig.port.toString(),
90
+ YOUCAN_API_KEY: this.app.remote_config.client_id,
91
+ YOUCAN_API_SECRET: this.app.remote_config.client_secret,
92
+ YOUCAN_API_SCOPES: this.app.remote_config.scopes.join(','),
93
+ APP_URL: this.app.network_config.app_url,
94
+ PORT: this.app.network_config.app_port.toString(),
85
95
  };
86
96
  }
87
97
  async openAppPreview() {
@@ -1,6 +1,6 @@
1
- import { Session, Tasks, Color } from '@youcan/cli-kit';
2
1
  import { AppCommand } from '../../../../util/app-command.js';
3
2
  import { load } from '../../../../util/app-loader.js';
3
+ import { Session, Tasks, Color } from '@youcan/cli-kit';
4
4
 
5
5
  class EnvShow extends AppCommand {
6
6
  static description = 'Display app environment variables';
@@ -16,13 +16,13 @@ class EnvShow extends AppCommand {
16
16
  await this.printEnvironmentVariables();
17
17
  }
18
18
  async printEnvironmentVariables() {
19
- if (!this.app.remoteConfig) {
19
+ if (!this.app.remote_config) {
20
20
  throw new Error('remote app config not loaded');
21
21
  }
22
22
  this.log();
23
- this.log(`${Color.yellow('YOUCAN_API_KEY')}=%s`, this.app.remoteConfig.client_id);
24
- this.log(`${Color.yellow('YOUCAN_API_SECRET')}=%s`, this.app.remoteConfig.client_secret);
25
- this.log(`${Color.yellow('YOUCAN_API_SCOPES')}=%s`, this.app.remoteConfig.scopes.join(','));
23
+ this.log(`${Color.yellow('YOUCAN_API_KEY')}=%s`, this.app.remote_config.client_id);
24
+ this.log(`${Color.yellow('YOUCAN_API_SECRET')}=%s`, this.app.remote_config.client_secret);
25
+ this.log(`${Color.yellow('YOUCAN_API_SCOPES')}=%s`, this.app.remote_config.scopes.join(','));
26
26
  }
27
27
  }
28
28
 
@@ -1,8 +1,8 @@
1
- import { Path, Filesystem, String, Tasks } from '@youcan/cli-kit';
2
- import { AppCommand } from '../../../../util/app-command.js';
3
1
  import extensions from '../../../services/generate/extensions/index.js';
4
2
  import { ensureExtensionDirectoryExists, initThemeExtension } from '../../../services/generate/generate.js';
5
3
  import { APP_CONFIG_FILENAME } from '../../../../constants.js';
4
+ import { AppCommand } from '../../../../util/app-command.js';
5
+ import { Path, Filesystem, String, Tasks } from '@youcan/cli-kit';
6
6
 
7
7
  class GenerateExtension extends AppCommand {
8
8
  static description = 'Generate an app extension';
@@ -1,6 +1,6 @@
1
- import { Session, Tasks, Http, Env, System } from '@youcan/cli-kit';
2
- import { load } from '../../../util/app-loader.js';
3
1
  import { AppCommand } from '../../../util/app-command.js';
2
+ import { load } from '../../../util/app-loader.js';
3
+ import { Session, Tasks, Http, Env, System } from '@youcan/cli-kit';
4
4
 
5
5
  class Install extends AppCommand {
6
6
  static description = 'Generate an app installation URL';
@@ -1,6 +1,6 @@
1
- import { Worker } from '@youcan/cli-kit';
2
- import type { App } from '@/types';
3
1
  import type DevCommand from '@/cli/commands/app/dev';
2
+ import type { App } from '@/types';
3
+ import { Worker } from '@youcan/cli-kit';
4
4
  export default class AppWorker extends Worker.Abstract {
5
5
  private command;
6
6
  private app;
@@ -1,5 +1,5 @@
1
- import { Worker, Filesystem, Path } from '@youcan/cli-kit';
2
1
  import { APP_CONFIG_FILENAME } from '../../../../constants.js';
2
+ import { Worker, Filesystem, Path } from '@youcan/cli-kit';
3
3
 
4
4
  class AppWorker extends Worker.Abstract {
5
5
  command;
@@ -1,10 +1,10 @@
1
+ import type DevCommand from '@/cli/commands/app/dev';
2
+ import type { App, Extension, Web } from '@/types';
3
+ import type { AppCommand } from '@/util/app-command';
1
4
  import type { Cli, Services, Worker } from '@youcan/cli-kit';
2
- import WebWorker from './web-worker';
3
5
  import AppWorker from './app-worker';
4
6
  import TunnelWorker from './tunnel-worker';
5
- import type { App, Extension, Web } from '@/types';
6
- import type DevCommand from '@/cli/commands/app/dev';
7
- import type { AppCommand } from '@/util/app-command';
7
+ import WebWorker from './web-worker';
8
8
  export interface ExtensionWorkerCtor {
9
9
  new (command: Cli.Command, app: App, extension: Extension): Worker.Interface;
10
10
  }
@@ -1,7 +1,7 @@
1
- import ThemeExtensionWorker from './theme-extension-worker.js';
2
- import WebWorker from './web-worker.js';
3
1
  import AppWorker from './app-worker.js';
2
+ import ThemeExtensionWorker from './theme-extension-worker.js';
4
3
  import TunnelWorker from './tunnel-worker.js';
4
+ import WebWorker from './web-worker.js';
5
5
 
6
6
  const EXTENSION_WORKERS = {
7
7
  theme: ThemeExtensionWorker,
@@ -1,6 +1,6 @@
1
+ import type { App, Extension } from '@/types';
1
2
  import type { Cli } from '@youcan/cli-kit';
2
3
  import { Worker } from '@youcan/cli-kit';
3
- import type { App, Extension } from '@/types';
4
4
  export default class ThemeExtensionWorker extends Worker.Abstract {
5
5
  private command;
6
6
  private app;
@@ -1,7 +1,7 @@
1
- import { Worker } from '@youcan/cli-kit';
2
- import type { Services } from '@youcan/cli-kit';
3
1
  import type { App } from '@/types';
4
2
  import type { AppCommand } from '@/util/app-command';
3
+ import type { Services } from '@youcan/cli-kit';
4
+ import { Worker } from '@youcan/cli-kit';
5
5
  export default class TunnelWorker extends Worker.Abstract {
6
6
  private command;
7
7
  private app;
@@ -12,4 +12,5 @@ export default class TunnelWorker extends Worker.Abstract {
12
12
  boot(): Promise<void>;
13
13
  run(): Promise<void>;
14
14
  private checkForError;
15
+ getUrl(): string;
15
16
  }
@@ -14,43 +14,40 @@ class TunnelWorker extends Worker.Abstract {
14
14
  this.logger = new Worker.Logger('tunnel', 'dim');
15
15
  }
16
16
  async boot() {
17
- if (!this.app.networkConfig) {
17
+ if (!this.app.network_config) {
18
18
  throw new Error('app network config is not set');
19
19
  }
20
20
  this.logger.write('start tunneling the app');
21
- await this.tunnelService.tunnel(this.app.networkConfig.port);
22
- // Stop the execution for while and see if the tunnel is available.
23
- await System.sleep(5);
24
- const url = this.tunnelService.getUrl();
25
- if (url) {
26
- this.logger.write(`tunneled url obtained: \`${url}\``);
27
- this.url = url;
28
- this.app.networkConfig.appUrl = this.url;
21
+ await this.tunnelService.tunnel(this.app.network_config.app_port);
22
+ let attempts = 0;
23
+ while (!this.url && attempts <= 28) {
24
+ const url = this.tunnelService.getUrl();
25
+ if (url) {
26
+ this.url = url;
27
+ this.app.network_config.app_url = this.url;
28
+ this.logger.write(`tunneled url obtained: \`${url}\``);
29
+ }
30
+ attempts++;
31
+ await System.sleep(0.5);
32
+ }
33
+ if (!this.url) {
34
+ this.logger.write('could not establish a tunnel, using localhost instead');
29
35
  }
30
36
  }
31
37
  async run() {
32
- const timeInterval = 500;
33
- if (this.url) {
34
- return;
35
- }
36
- setInterval(() => {
37
- if (this.url !== null) {
38
- this.checkForError();
39
- return;
40
- }
41
- this.url = this.tunnelService.getUrl();
42
- if (this.url) {
43
- this.logger.write(`tunneled url obtained: \`${this.url}\``);
44
- this.app.networkConfig.appUrl = this.url;
45
- this.command.syncAppConfig();
46
- }
47
- }, timeInterval);
38
+ setInterval(() => this.checkForError, 500);
48
39
  }
49
40
  checkForError() {
50
41
  const error = this.tunnelService.getError();
51
42
  if (error) {
52
- throw new Error(`Tunnel stopped: ${error}`);
43
+ throw new Error(`tunnel stopped: ${error}`);
44
+ }
45
+ }
46
+ getUrl() {
47
+ if (!this.url) {
48
+ throw new Error('app url not set');
53
49
  }
50
+ return this.url;
54
51
  }
55
52
  }
56
53
 
@@ -1,5 +1,5 @@
1
- import { type Cli, Worker } from '@youcan/cli-kit';
2
1
  import type { App, Web } from '@/types';
2
+ import { type Cli, Worker } from '@youcan/cli-kit';
3
3
  export default class WebWorker extends Worker.Abstract {
4
4
  private readonly command;
5
5
  private readonly app;
@@ -1,5 +1,5 @@
1
- import { Path, Filesystem, Git } from '@youcan/cli-kit';
2
1
  import { EXTENSION_CONFIG_FILENAME } from '../../../constants.js';
2
+ import { Path, Filesystem, Git } from '@youcan/cli-kit';
3
3
 
4
4
  async function ensureExtensionDirectoryExists(name) {
5
5
  const dir = Path.join(Path.cwd(), 'extensions', name);
package/dist/types.d.ts CHANGED
@@ -64,10 +64,10 @@ export interface App {
64
64
  root: string;
65
65
  webs: Web[];
66
66
  config: AppConfig;
67
- remoteConfig?: RemoteAppConfig;
68
- networkConfig?: {
69
- appUrl: string;
70
- port: number;
67
+ remote_config?: RemoteAppConfig;
68
+ network_config?: {
69
+ app_url: string;
70
+ app_port: number;
71
71
  };
72
72
  extensions: Extension[];
73
73
  }
@@ -1,6 +1,6 @@
1
+ import type { App } from '@/types';
1
2
  import type { Session } from '@youcan/cli-kit';
2
3
  import { Cli } from '@youcan/cli-kit';
3
- import type { App } from '@/types';
4
4
  export declare abstract class AppCommand extends Cli.Command {
5
5
  protected app: App;
6
6
  protected session: Session.StoreSession;
@@ -1,5 +1,5 @@
1
- import { Cli, Env, Http, Filesystem, Path } from '@youcan/cli-kit';
2
1
  import { APP_CONFIG_FILENAME } from '../constants.js';
2
+ import { Cli, Env, Http, Filesystem, Path } from '@youcan/cli-kit';
3
3
 
4
4
  class AppCommand extends Cli.Command {
5
5
  app;
@@ -8,18 +8,12 @@ class AppCommand extends Cli.Command {
8
8
  const endpoint = this.app.config.id == null
9
9
  ? `${Env.apiHostname()}/apps/create`
10
10
  : `${Env.apiHostname()}/apps/${this.app.config.id}/update`;
11
- if (!this.app.networkConfig) {
12
- throw new Error('app network config is not set');
13
- }
14
- const backUrl = new URL('/auth/callback', this.app.networkConfig.appUrl).toString();
15
11
  const res = await Http.post(endpoint, {
16
12
  headers: { Authorization: `Bearer ${this.session.access_token}` },
17
13
  body: JSON.stringify({
18
14
  name: this.app.config.name,
19
- app_url: this.app.networkConfig.appUrl,
20
- redirect_urls: [
21
- backUrl,
22
- ],
15
+ app_url: this.app.config.app_url,
16
+ redirect_urls: this.app.config.redirect_urls,
23
17
  }),
24
18
  });
25
19
  this.app.config = {
@@ -33,7 +27,7 @@ class AppCommand extends Cli.Command {
33
27
  },
34
28
  };
35
29
  await Filesystem.writeJsonFile(Path.join(this.app.root, APP_CONFIG_FILENAME), this.app.config);
36
- this.app.remoteConfig = res;
30
+ this.app.remote_config = res;
37
31
  return this.app;
38
32
  }
39
33
  }
@@ -1,5 +1,5 @@
1
- import { Path, Filesystem } from '@youcan/cli-kit';
2
1
  import { APP_CONFIG_FILENAME, DEFAULT_EXTENSIONS_DIR, EXTENSION_CONFIG_FILENAME, DEFAULT_WEBS_DIR, WEB_CONFIG_FILENAME } from '../constants.js';
2
+ import { Path, Filesystem } from '@youcan/cli-kit';
3
3
 
4
4
  async function load() {
5
5
  const path = Path.resolve(Path.cwd(), APP_CONFIG_FILENAME);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@youcan/app",
3
3
  "type": "module",
4
- "version": "2.3.0",
4
+ "version": "2.3.2",
5
5
  "description": "OCLIF plugin for building apps",
6
6
  "author": "YouCan <contact@youcan.shop> (https://youcan.shop)",
7
7
  "license": "MIT",
@@ -17,7 +17,7 @@
17
17
  "dependencies": {
18
18
  "@oclif/core": "^2.15.0",
19
19
  "dayjs": "^1.11.10",
20
- "@youcan/cli-kit": "2.3.0"
20
+ "@youcan/cli-kit": "2.3.2"
21
21
  },
22
22
  "devDependencies": {
23
23
  "@oclif/plugin-legacy": "^1.3.0",