@linktr.ee/create-link-app 2.0.0-rc.1 โ†’ 2.1.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.
package/README.md CHANGED
@@ -29,7 +29,6 @@ npx @linktr.ee/create-link-app --help
29
29
  * [`create-link-app create NAME`](#create-link-app-create-name)
30
30
  * [`create-link-app deploy`](#create-link-app-deploy)
31
31
  * [`create-link-app dev`](#create-link-app-dev)
32
- * [`create-link-app generate-types`](#create-link-app-generate-types)
33
32
  * [`create-link-app grant-access LINK_APP_ID USERNAME`](#create-link-app-grant-access-link_app_id-username)
34
33
  * [`create-link-app help [COMMAND]`](#create-link-app-help-command)
35
34
  * [`create-link-app login`](#create-link-app-login)
@@ -43,10 +42,11 @@ Build Link App project to static assets used for production
43
42
 
44
43
  ```
45
44
  USAGE
46
- $ create-link-app build [--native]
45
+ $ create-link-app build [--native] [--profile]
47
46
 
48
47
  FLAGS
49
- --native Build native components of a Link App ready for publishing to npm
48
+ --native Build native components of a Link App ready for publishing to npm
49
+ --profile Enable detailed webpack profiling and bundle analysis
50
50
 
51
51
  DESCRIPTION
52
52
  Build Link App project to static assets used for production
@@ -58,16 +58,14 @@ Initialize a new Link App project
58
58
 
59
59
  ```
60
60
  USAGE
61
- $ create-link-app create NAME [-t react|react-ts] [-p <value>] [--storybook]
61
+ $ create-link-app create NAME [-p <value>] [--storybook]
62
62
 
63
63
  ARGUMENTS
64
64
  NAME Name of the Link App
65
65
 
66
66
  FLAGS
67
- -p, --path=<value> Path to create the project in
68
- -t, --template=<option> [default: react-ts] Template to use for the project
69
- <options: react|react-ts>
70
- --storybook With Storybook added to the project
67
+ -p, --path=<value> Path to create the project in
68
+ --storybook With Storybook added to the project
71
69
 
72
70
  DESCRIPTION
73
71
  Initialize a new Link App project
@@ -75,9 +73,9 @@ DESCRIPTION
75
73
  EXAMPLES
76
74
  $ create-link-app create my-link-app
77
75
 
78
- $ create-link-app create my-link-app --template react
79
-
80
76
  $ create-link-app create my-link-app --path my/custom/path
77
+
78
+ $ create-link-app create my-link-app --storybook
81
79
  ```
82
80
 
83
81
  ## `create-link-app deploy`
@@ -122,18 +120,6 @@ EXAMPLES
122
120
  $ create-link-app dev --https
123
121
  ```
124
122
 
125
- ## `create-link-app generate-types`
126
-
127
- Generate Typescript types from the schema definitions
128
-
129
- ```
130
- USAGE
131
- $ create-link-app generate-types
132
-
133
- DESCRIPTION
134
- Generate Typescript types from the schema definitions
135
- ```
136
-
137
123
  ## `create-link-app grant-access LINK_APP_ID USERNAME`
138
124
 
139
125
  Grant access to other developers to push updates for your Link App
@@ -11,19 +11,30 @@ const child_process_1 = require("child_process");
11
11
  class Build extends base_1.default {
12
12
  async run() {
13
13
  const { flags } = await this.parse(Build);
14
+ const allowAnyOrigin = flags['allow-any-origin'];
15
+ this.log('๐Ÿ—๏ธ Starting build process...');
14
16
  if (flags['native']) {
17
+ this.log('๐Ÿ“ฑ Building native components...');
15
18
  this.native();
16
19
  }
17
20
  else {
18
- this.webpack({
19
- allowAnyOrigin: flags['allow-any-origin'],
21
+ await this.webpack({
22
+ allowAnyOrigin,
23
+ profile: flags.profile,
20
24
  });
21
25
  }
22
26
  this.log('๐ŸŽ‰ Build complete');
23
27
  }
24
28
  async webpack(options) {
29
+ this.log('โฑ๏ธ Starting webpack build...');
30
+ const configStartTime = Date.now();
25
31
  const config = await (0, webpack_config_1.default)('production', options);
32
+ const configEndTime = Date.now();
33
+ this.log(`๐Ÿ“‹ Webpack config generated in ${configEndTime - configStartTime}ms`);
34
+ const buildStartTime = Date.now();
26
35
  (0, webpack_1.default)(config, (err, stats) => {
36
+ const buildEndTime = Date.now();
37
+ const totalTime = buildEndTime - buildStartTime;
27
38
  if (err) {
28
39
  this.error(err);
29
40
  }
@@ -33,10 +44,73 @@ class Build extends base_1.default {
33
44
  else if (stats?.hasWarnings()) {
34
45
  this.warn(stats.toString());
35
46
  }
47
+ else {
48
+ this.log(`โšก Webpack build completed in ${totalTime}ms`);
49
+ // Display detailed timing information if available
50
+ if (stats?.compilation?.logging) {
51
+ const compilation = stats.compilation;
52
+ this.log('\n๐Ÿ“Š Build Performance Summary:');
53
+ // Show module count and timing
54
+ const moduleCount = compilation.modules?.size || 0;
55
+ this.log(` ๐Ÿ“ฆ Modules processed: ${moduleCount}`);
56
+ // Show asset information
57
+ const assets = Object.keys(stats.compilation.assets || {});
58
+ if (assets.length > 0) {
59
+ this.log(` ๐Ÿ—‚๏ธ Assets generated: ${assets.length}`);
60
+ // Show largest assets
61
+ const assetSizes = assets
62
+ .map((name) => ({
63
+ name,
64
+ size: stats?.compilation.assets[name]?.size() || 0,
65
+ }))
66
+ .sort((a, b) => b.size - a.size)
67
+ .slice(0, 5);
68
+ this.log(' ๐Ÿ“ Largest assets:');
69
+ assetSizes.forEach((asset) => {
70
+ const sizeKB = (asset.size / 1024).toFixed(1);
71
+ this.log(` ${asset.name}: ${sizeKB}KB`);
72
+ });
73
+ }
74
+ }
75
+ // Show timing breakdown if stats are available
76
+ if (stats?.toString) {
77
+ const statsString = stats.toString({
78
+ colors: false,
79
+ modules: false,
80
+ chunks: false,
81
+ timings: true,
82
+ performance: true,
83
+ });
84
+ // Extract timing information from stats
85
+ const timingMatch = statsString.match(/Time: (\d+)ms/i);
86
+ if (timingMatch) {
87
+ this.log(` โฑ๏ธ Webpack internal timing: ${timingMatch[1]}ms`);
88
+ }
89
+ }
90
+ // Provide guidance for further analysis
91
+ if (options.profile) {
92
+ this.log('\n๐Ÿ“Š Bundle analysis files generated:');
93
+ this.log(' ๐Ÿ“„ Bundle report: dist/bundle-report.html');
94
+ this.log(' ๐Ÿ“ˆ Webpack stats: dist/webpack-stats.json');
95
+ this.log(' ๐Ÿ’ก Open bundle-report.html in your browser to analyze bundle size');
96
+ this.log('\n๐Ÿ” Detailed profiling enabled - check webpack output above for timing breakdown');
97
+ }
98
+ }
36
99
  });
37
100
  }
38
101
  async native() {
39
- (0, child_process_1.spawn)('npx react-native-builder-bob build', { cwd: process.cwd(), shell: true, stdio: 'inherit' });
102
+ const nativeProcess = (0, child_process_1.spawn)('npx react-native-builder-bob build', { cwd: process.cwd(), shell: true, stdio: 'inherit' });
103
+ nativeProcess.on('error', (err) => {
104
+ this.error(`โŒ Failed to build native components: ${err.message}`);
105
+ });
106
+ nativeProcess.on('close', (code) => {
107
+ if (code === 0) {
108
+ this.log('โœ… Native components built successfully');
109
+ }
110
+ else {
111
+ this.error(`โŒ Native build failed with exit code ${code}`);
112
+ }
113
+ });
40
114
  }
41
115
  }
42
116
  exports.default = Build;
@@ -49,4 +123,7 @@ Build.flags = {
49
123
  native: core_1.Flags.boolean({
50
124
  description: 'Build native components of a Link App ready for publishing to npm',
51
125
  }),
126
+ profile: core_1.Flags.boolean({
127
+ description: 'Enable detailed webpack profiling and bundle analysis',
128
+ }),
52
129
  };
@@ -13,29 +13,31 @@ class Create extends base_1.default {
13
13
  async run() {
14
14
  const { args, flags } = await this.parse(Create);
15
15
  const targetDir = path_1.default.resolve(flags.path ?? process.cwd(), args.name);
16
- this.log(`๐Ÿ”— Creating project in ${targetDir}...`);
16
+ this.log(`๐Ÿ”— Creating Link App project '${args.name}' in ${targetDir}...`);
17
17
  if (flags.storybook) {
18
- this.log(' ๐ŸŽจ Including Storybook in the project...');
18
+ this.log('๐ŸŽจ Including Storybook in the project...');
19
19
  }
20
- await (0, create_project_1.default)(flags.template, targetDir, { hasStorybook: flags.storybook });
20
+ await (0, create_project_1.default)(targetDir, { hasStorybook: flags.storybook });
21
21
  const useYarn = (0, is_using_yarn_1.default)();
22
- core_1.CliUx.ux.action.start(' ๐Ÿšš Installing dependencies');
22
+ core_1.CliUx.ux.action.start('๐Ÿšš Installing dependencies');
23
23
  (0, install_dependencies_1.default)(targetDir, useYarn);
24
24
  core_1.CliUx.ux.action.stop();
25
25
  const relativeProjectPath = path_1.default.relative(process.cwd(), targetDir);
26
- this.log('\nโœ… Project created, to get started:');
26
+ this.log('โœ… Project created successfully!');
27
+ this.log('\n๐Ÿš€ To get started:');
27
28
  this.log(` cd ${relativeProjectPath}`);
28
29
  this.log(` yarn install | npm install`);
29
30
  this.log(` yarn build | npm run build`);
30
- this.log(` yarn dev | npm run dev\n`);
31
+ this.log(` yarn dev | npm run dev`);
32
+ this.log('\n๐ŸŽ‰ Happy coding!');
31
33
  }
32
34
  }
33
35
  exports.default = Create;
34
36
  Create.description = 'Initialize a new Link App project';
35
37
  Create.examples = [
36
38
  '$ create-link-app create my-link-app',
37
- '$ create-link-app create my-link-app --template react',
38
39
  '$ create-link-app create my-link-app --path my/custom/path',
40
+ '$ create-link-app create my-link-app --storybook',
39
41
  ];
40
42
  Create.args = [
41
43
  {
@@ -45,12 +47,6 @@ Create.args = [
45
47
  },
46
48
  ];
47
49
  Create.flags = {
48
- template: core_1.Flags.string({
49
- char: 't',
50
- description: 'Template to use for the project',
51
- options: ['react', 'react-ts'],
52
- default: 'react-ts',
53
- }),
54
50
  path: core_1.Flags.string({
55
51
  char: 'p',
56
52
  description: 'Path to create the project in',
@@ -23,30 +23,31 @@ class Deploy extends base_1.default {
23
23
  const isForceUpdate = !!flags['force-update'];
24
24
  const isQa = !!flags.qa;
25
25
  if (isForceUpdate) {
26
- this.log('โš ๏ธ "--force-update" flag will impact the existing PUBLISHED Link Apps.\n');
26
+ this.log('โš ๏ธ "--force-update" flag will impact the existing PUBLISHED Link Apps.');
27
27
  }
28
- this.log(`๐Ÿ“ฆ Packing project...\n`);
28
+ this.log('๐Ÿš€ Starting deployment process...');
29
+ this.log('๐Ÿ“ฆ Packing project...');
29
30
  const packedFiles = await (0, pack_project_1.default)(flags.path);
30
31
  const linkAppName = this.getLinkAppId(flags.path);
31
32
  const linkAppId = (0, slugify_1.default)(linkAppName, { lower: true });
32
- this.log(`๐Ÿ” Checking Link App by ID: [${linkAppId}] ...\n`);
33
+ this.log(`๐Ÿ” Checking Link App by ID: [${linkAppId}]...`);
33
34
  const linkAppExists = await (0, check_link_app_exists_1.default)(linkTypeServiceUrl, linkAppId, accessToken);
34
35
  if (linkAppExists) {
35
- this.log(` Link App [${linkAppId}] already exists, updating it...`);
36
+ this.log(`โœ… Link App [${linkAppId}] already exists, updating it...`);
36
37
  }
37
38
  else {
38
- this.log(` Link App [${linkAppId}] does not exist, creating it...`);
39
+ this.log(`๐Ÿ†• Link App [${linkAppId}] does not exist, creating it...`);
39
40
  }
40
41
  if (packedFiles?.length) {
41
- this.log(' Ready to upload the following files:');
42
+ this.log('๐Ÿ“‹ Ready to upload the following files:');
42
43
  packedFiles.forEach((file) => {
43
- this.log(` - ${file}`);
44
+ this.log(` ๐Ÿ“„ ${file}`);
44
45
  });
45
46
  }
46
47
  if (!flags['skip-confirm']) {
47
48
  const userConfirmDeploy = await core_1.CliUx.ux.prompt(`โ“ ${isQa ? '[QA]' : ''} Do you want to proceed? (Y/n)`, { required: false });
48
49
  if (userConfirmDeploy?.toLowerCase() !== 'y') {
49
- this.log('Aborted!');
50
+ this.log('โŒ Deployment aborted!');
50
51
  return;
51
52
  }
52
53
  }
@@ -69,7 +70,7 @@ class Deploy extends base_1.default {
69
70
  }
70
71
  }
71
72
  async processSuccess(flags, result) {
72
- this.log(`\n--------------------------------`);
73
+ this.log('\n๐Ÿ“Š Deployment Response:');
73
74
  this.log(JSON.stringify(result, null, 2));
74
75
  const linkTypeId = result.linkType.linkTypeId;
75
76
  const buildId = result.build?.id;
@@ -79,15 +80,15 @@ class Deploy extends base_1.default {
79
80
  const linkAppCreateUrl = flags.qa
80
81
  ? `https://qa.linktr.ee/admin?action=create-link&linkType=${linkTypeId}`
81
82
  : `https://linktr.ee/admin?action=create-link&linkType=${linkTypeId}`;
82
- this.log(`\n--------------------------------`);
83
+ this.log('\n๐ŸŽ‰ Deployment Summary:');
83
84
  this.log(`โœ… Link App successfully ${flags.update ? 'updated' : 'uploaded'}`);
84
- this.log(` - Link App ID: ${linkTypeId}`);
85
- this.log(` - Status: ${result.linkType.status}`);
86
- this.log(` - Updated: ${new Date(result.linkType.updated_timestamp * 1000).toLocaleString()}`);
85
+ this.log(`๐Ÿ†” Link App ID: ${linkTypeId}`);
86
+ this.log(`๐Ÿ“Š Status: ${result.linkType.status}`);
87
+ this.log(`๐Ÿ•’ Updated: ${new Date(result.linkType.updated_timestamp * 1000).toLocaleString()}`);
87
88
  if (buildId) {
88
- this.log(` - Check Link App build: ${linkAppBuildUrl}`);
89
+ this.log(`๐Ÿ”— Check Link App build: ${linkAppBuildUrl}`);
89
90
  }
90
- this.log(` - Create Link App: ${linkAppCreateUrl}`);
91
+ this.log(`๐Ÿš€ Create Link App: ${linkAppCreateUrl}`);
91
92
  }
92
93
  getLinkAppId(givenPath) {
93
94
  const manifestPath = path_1.default.resolve(givenPath ?? process.cwd(), 'manifest.json');
@@ -11,6 +11,7 @@ const webpack_config_1 = __importDefault(require("../webpack/webpack.config"));
11
11
  class Dev extends base_1.default {
12
12
  async run() {
13
13
  const { flags } = await this.parse(Dev);
14
+ this.log('๐Ÿš€ Starting development server...');
14
15
  const config = await (0, webpack_config_1.default)('development');
15
16
  const devServer = new webpack_dev_server_1.default({
16
17
  client: {
@@ -22,7 +23,9 @@ class Dev extends base_1.default {
22
23
  port: flags.port,
23
24
  allowedHosts: flags.allowedHosts,
24
25
  }, (0, webpack_1.default)(config));
26
+ this.log(`๐Ÿ“ก Development server will start on ${flags.https ? 'https' : 'http'}://${flags.host}:${flags.port}`);
25
27
  await devServer.start();
28
+ this.log('โœ… Development server started successfully');
26
29
  }
27
30
  }
28
31
  exports.default = Dev;
@@ -10,6 +10,7 @@ const access_token_1 = require("../lib/auth/access-token");
10
10
  class GrantAccess extends base_1.default {
11
11
  async run() {
12
12
  const { args, flags } = await this.parse(GrantAccess);
13
+ this.log(`๐Ÿ” Granting access to Link App '${args.link_app_id}' for user '${args.username}'...`);
13
14
  const appConfig = await this.getAppConfig(flags.qa ? 'qa' : 'production');
14
15
  const accessToken = (0, access_token_1.getAccessToken)(appConfig.auth.audience);
15
16
  const url = `${flags.endpoint ?? appConfig.link_types_url}/link-types/${args.link_app_id}/maintainers`;
@@ -23,10 +24,10 @@ class GrantAccess extends base_1.default {
23
24
  };
24
25
  try {
25
26
  await axios_1.default.post(url, maintainerDto, { headers });
26
- this.log(`Successfully granted maintainer access to user '${args.username}'\n`);
27
+ this.log(`โœ… Successfully granted maintainer access to user '${args.username}'`);
27
28
  }
28
29
  catch (err) {
29
- this.log('There was an error while attempting to grant access to user\n');
30
+ this.log(`โŒ There was an error while attempting to grant access to user '${args.username}'`);
30
31
  if (axios_1.default.isAxiosError(err)) {
31
32
  if (err.response) {
32
33
  this.error(JSON.stringify(err.response.data, null, 2));
@@ -10,25 +10,26 @@ const device_auth_1 = require("../lib/auth/device-auth");
10
10
  class Login extends base_1.default {
11
11
  async run() {
12
12
  const { flags } = await this.parse(Login);
13
+ this.log('๐Ÿ” Initiating login with Linktree credentials...');
13
14
  const appConfig = await this.getAppConfig(flags.qa ? 'qa' : 'production');
14
15
  const handle = await (0, device_auth_1.initDeviceAuthorization)(appConfig.auth);
15
16
  const { expires_in, user_code, verification_uri_complete } = handle;
16
17
  const expiryTime = expires_in % 60 === 0 ? `${expires_in / 60} minutes` : `${expires_in} seconds`;
17
- this.log(`Please login via the opened web browser link. The browser window should display the following code: ${user_code}`);
18
- this.log(`If browser does not open automatically, please go to the following link: ${verification_uri_complete}`);
19
- this.log(`This link expires in ${expiryTime}. Press Ctrl-C to abort.\n`);
18
+ this.log(`๐ŸŒ Please login via the opened web browser link. The browser window should display the following code: ${user_code}`);
19
+ this.log(`๐Ÿ”— If browser does not open automatically, please go to the following link: ${verification_uri_complete}`);
20
+ this.log(`โฐ This link expires in ${expiryTime}. Press Ctrl-C to abort.`);
20
21
  core_1.CliUx.ux.open(verification_uri_complete);
21
- core_1.CliUx.ux.action.start('Waiting for user to authorize device from browser');
22
+ core_1.CliUx.ux.action.start('โณ Waiting for user to authorize device from browser');
22
23
  const token = await (0, device_auth_1.pollAccessToken)(handle);
23
24
  core_1.CliUx.ux.action.stop();
24
25
  if ((0, access_token_1.isTokenValid)(token)) {
25
26
  (0, access_token_1.saveAccessToken)(token.access_token);
26
27
  if (flags.qa) {
27
- this.log('TOKEN: ', token.access_token);
28
+ this.log('๐Ÿ”‘ TOKEN: ', token.access_token);
28
29
  }
29
- this.log('\nDevice has been authorized. Login successful.');
30
+ this.log('โœ… Device has been authorized. Login successful.');
30
31
  if (token.expires_at) {
31
- this.log(`Login will expire at ${new Date(token.expires_at * 1000).toString()}\n`);
32
+ this.log(`โฐ Login will expire at ${new Date(token.expires_at * 1000).toString()}`);
32
33
  }
33
34
  }
34
35
  }
@@ -9,6 +9,7 @@ const access_token_1 = require("../lib/auth/access-token");
9
9
  class Logout extends base_1.default {
10
10
  async run() {
11
11
  const { flags } = await this.parse(Logout);
12
+ this.log('๐Ÿ”“ Logging out and clearing browser session...');
12
13
  const appConfig = await this.getAppConfig(flags.qa ? 'qa' : 'production');
13
14
  const { auth, logout_redirect_url } = appConfig;
14
15
  const { domain, client_id, audience } = auth;
@@ -16,8 +17,8 @@ class Logout extends base_1.default {
16
17
  // clear Auth0 session cookies so user gets prompted to enter credentials again for next login
17
18
  const url = `${domain}/v2/logout?client_id=${client_id}&returnTo=${logout_redirect_url}`;
18
19
  core_1.CliUx.ux.open(url);
19
- this.log('Logout successful.');
20
- this.log(`If browser did not open automatically, please go to the following link to logout from the browser: ${url}`);
20
+ this.log('โœ… Logout successful.');
21
+ this.log(`๐ŸŒ If browser did not open automatically, please go to the following link to logout from the browser: ${url}`);
21
22
  }
22
23
  }
23
24
  exports.default = Logout;
@@ -11,10 +11,12 @@ class Storybook extends base_1.default {
11
11
  async run() {
12
12
  const configPath = path_1.default.resolve(__dirname, '..', 'storybook');
13
13
  const { flags } = await this.parse(Storybook);
14
+ this.log(`๐Ÿ“š Starting Storybook development server on port ${flags.port}...`);
14
15
  const storybook = (0, child_process_1.spawn)(`start-storybook -p ${flags.port} -c ${configPath}`, { shell: true, stdio: 'inherit' });
15
16
  storybook.on('error', (err) => {
16
- throw err;
17
+ this.error(`โŒ Failed to start Storybook: ${err.message}`);
17
18
  });
19
+ this.log('โœ… Storybook server started successfully');
18
20
  }
19
21
  }
20
22
  exports.default = Storybook;
@@ -12,6 +12,7 @@ const test_url_match_rules_1 = __importDefault(require("../lib/deploy/test-url-m
12
12
  class TestUrlMatchRules extends base_1.default {
13
13
  async run() {
14
14
  const { args, flags } = await this.parse(TestUrlMatchRules);
15
+ this.log(`๐Ÿงช Testing URL match rules for: ${args.url}`);
15
16
  const appConfig = await this.getAppConfig(flags.qa ? 'qa' : 'production');
16
17
  const linkTypeServiceUrl = `${flags.endpoint ?? appConfig.link_types_url}/link-types`;
17
18
  const accessToken = (0, access_token_1.getAccessToken)(appConfig.auth.audience);
@@ -24,6 +25,7 @@ class TestUrlMatchRules extends base_1.default {
24
25
  if (!fs_1.default.existsSync(urlMatchRulesPath)) {
25
26
  this.error('โŒ url_match_rules.json not found', { exit: 1 });
26
27
  }
28
+ this.log('๐Ÿ“‹ Loading URL match rules from url_match_rules.json...');
27
29
  const urlMatchRulesString = fs_1.default.readFileSync(urlMatchRulesPath, 'utf8');
28
30
  if (!urlMatchRulesString) {
29
31
  this.error('โŒ url_match_rules.json is empty');
@@ -31,11 +33,13 @@ class TestUrlMatchRules extends base_1.default {
31
33
  let urlMatchRules = null;
32
34
  try {
33
35
  urlMatchRules = JSON.parse(urlMatchRulesString);
36
+ this.log('โœ… URL match rules loaded successfully');
34
37
  }
35
38
  catch (error) {
36
39
  this.error('โŒ url_match_rules.json is invalid');
37
40
  }
38
41
  try {
42
+ this.log('๐Ÿ” Testing URL against match rules...');
39
43
  const result = await (0, test_url_match_rules_1.default)(linkTypeServiceUrl, url, urlMatchRules, accessToken);
40
44
  const success = result.success;
41
45
  this.log(`${success ? '๐ŸŽ‰' : 'โŒ'} Test URL Match Rules Result:`);
@@ -8,8 +8,8 @@ const path_1 = __importDefault(require("path"));
8
8
  const project_name_to_title_1 = __importDefault(require("./project-name-to-title"));
9
9
  // templates path relative to this module
10
10
  const BaseTemplatesDir = path_1.default.resolve(__dirname, '..', '..', '..', 'templates');
11
- const createProject = async (template, targetDir, options) => {
12
- const templateDir = path_1.default.resolve(BaseTemplatesDir, template);
11
+ const createProject = async (targetDir, options) => {
12
+ const templateDir = path_1.default.resolve(BaseTemplatesDir, 'react-ts');
13
13
  const templateCommonDir = path_1.default.resolve(BaseTemplatesDir, 'common');
14
14
  await fs_extra_1.default.copy(templateDir, targetDir);
15
15
  await fs_extra_1.default.copy(templateCommonDir, targetDir);
@@ -28,64 +28,33 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
28
28
  Object.defineProperty(exports, "__esModule", { value: true });
29
29
  const react_1 = __importStar(require("react"));
30
30
  const client_1 = require("react-dom/client");
31
- const simulator_1 = __importDefault(require("./simulator"));
32
31
  const extension_1 = __importDefault(require("@linktr.ee/extension"));
33
32
  const extension_dev_data_1 = __importDefault(require("@linktr.ee/extension-dev-data"));
34
33
  const container = document.getElementById('root');
35
34
  const root = (0, client_1.createRoot)(container);
36
- function EmbeddedExtension() {
37
- const wrapperRef = (0, react_1.useRef)(null);
38
- const [extensionData, setExtensionData] = (0, react_1.useState)(extension_dev_data_1.default);
35
+ const App = () => {
36
+ // TODO: refactor common postMessage to parent in both entry points
39
37
  (0, react_1.useEffect)(() => {
40
- const postReady = (height) => {
41
- const ready = { type: 'extension-ready', data: { ready: true, height } };
42
- window.parent.postMessage(ready, '*');
43
- };
44
- // signal loaded first, then report initial size
45
- const loaded = { type: 'extension-loaded', data: { loaded: true } };
46
- window.parent.postMessage(loaded, '*');
47
- const initialHeight = Math.ceil(wrapperRef.current?.getBoundingClientRect().height || document.documentElement.scrollHeight || container.clientHeight);
48
- postReady(initialHeight);
49
- const ro = new window.ResizeObserver((entries) => {
50
- const entry = entries[0];
51
- const h = Math.ceil(entry?.contentRect?.height || wrapperRef.current?.getBoundingClientRect().height || 0);
52
- if (h)
53
- postReady(h);
54
- });
55
- if (wrapperRef.current)
56
- ro.observe(wrapperRef.current);
57
- const onMessage = (event) => {
58
- if (event.data?.type === 'extension-data') {
59
- const data = event.data?.data || {};
60
- // eslint-disable-next-line no-console
61
- console.info('[Extension] received extension-data', data);
62
- setExtensionData((prev) => ({ ...prev, ...data }));
63
- }
64
- };
65
- // forward interaction events to the parent (parity with production)
66
- const onInteraction = (event) => window.parent.postMessage({ type: 'interaction-event', data: event.detail }, '*');
67
- document.addEventListener('interaction-event', onInteraction);
68
- window.addEventListener('message', onMessage);
69
- return () => {
70
- if (wrapperRef.current) {
71
- try {
72
- ro.unobserve(wrapperRef.current);
73
- }
74
- catch (e) {
75
- // ignore unobserve errors in dev simulator
76
- }
77
- }
78
- document.removeEventListener('interaction-event', onInteraction);
79
- window.removeEventListener('message', onMessage);
38
+ const message = {
39
+ type: 'extension-ready',
40
+ data: {
41
+ ready: true,
42
+ height: container.clientHeight,
43
+ },
80
44
  };
45
+ window.parent.postMessage(message, '*');
81
46
  }, []);
82
- return (react_1.default.createElement("div", { ref: wrapperRef, style: { display: 'block' } },
83
- react_1.default.createElement(extension_1.default, { ...extensionData })));
84
- }
85
- const App = () => {
86
47
  if (window.location.search === '?embed') {
87
- return react_1.default.createElement(EmbeddedExtension, null);
48
+ return react_1.default.createElement(extension_1.default, { ...extension_dev_data_1.default });
49
+ }
50
+ else {
51
+ return (react_1.default.createElement("iframe", { src: `${window.location}?embed`, sandbox: ['allow-scripts', 'allow-same-origin', 'allow-popups', 'allow-popups-to-escape-sandbox', 'allow-forms'].join(' '), scrolling: "no", frameBorder: 0, style: {
52
+ display: 'block',
53
+ margin: '0 auto',
54
+ width: '1px',
55
+ minWidth: '680px',
56
+ height: '100vh',
57
+ } }));
88
58
  }
89
- return react_1.default.createElement(simulator_1.default, null);
90
59
  };
91
60
  root.render(react_1.default.createElement(App, null));