@youcan/app 2.3.0 → 2.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,8 @@
1
- import { Session, Tasks, UI, System, Services, Env, Http } from '@youcan/cli-kit';
1
+ import { Session, Tasks, UI, System, Services, Filesystem, Path, Env, Http } from '@youcan/cli-kit';
2
2
  import { bootTunnelWorker, bootAppWorker, bootWebWorker, bootExtensionWorker } from '../../services/dev/workers/index.js';
3
3
  import { AppCommand } from '../../../util/app-command.js';
4
4
  import { load } from '../../../util/app-loader.js';
5
+ import { APP_CONFIG_FILENAME } from '../../../constants.js';
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() {
@@ -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
 
@@ -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,39 @@ 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
+ await System.sleep(0.5);
31
+ }
32
+ if (!this.url) {
33
+ this.logger.write('could not establish a tunnel, using localhost instead');
29
34
  }
30
35
  }
31
36
  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);
37
+ setInterval(() => this.checkForError, 500);
48
38
  }
49
39
  checkForError() {
50
40
  const error = this.tunnelService.getError();
51
41
  if (error) {
52
- throw new Error(`Tunnel stopped: ${error}`);
42
+ throw new Error(`tunnel stopped: ${error}`);
43
+ }
44
+ }
45
+ getUrl() {
46
+ if (!this.url) {
47
+ throw new Error('app url not set');
53
48
  }
49
+ return this.url;
54
50
  }
55
51
  }
56
52
 
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
  }
@@ -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
  }
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.1",
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.1"
21
21
  },
22
22
  "devDependencies": {
23
23
  "@oclif/plugin-legacy": "^1.3.0",