@slicemachine/init 1.1.10-alpha.5 → 1.1.11-alpha.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.
package/src/index.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { CONSTS } from "@slicemachine/core";
1
+ import { ApplicationMode } from "@slicemachine/client";
2
2
  import Prismic from "@slicemachine/core/build/prismic";
3
3
  import Tracker from "./utils/tracker";
4
4
  import {
@@ -12,17 +12,29 @@ import {
12
12
  installLib,
13
13
  sendStarterData,
14
14
  } from "./steps";
15
- import { findArgument, logs, findFlag } from "./utils";
15
+ import {
16
+ findArgument,
17
+ findFlag,
18
+ logs,
19
+ getApplicationMode,
20
+ InitClient,
21
+ } from "./utils";
22
+ import { Models } from "@slicemachine/core";
16
23
 
17
24
  async function init() {
18
25
  const cwd = findArgument(process.argv, "cwd") || process.cwd();
19
- const base = findArgument(process.argv, "base") || CONSTS.DEFAULT_BASE;
26
+ const mode: ApplicationMode =
27
+ getApplicationMode(findArgument(process.argv, "mode")) ||
28
+ ApplicationMode.PROD;
20
29
  const lib: string | undefined = findArgument(process.argv, "library");
21
30
  const branch: string | undefined = findArgument(process.argv, "branch");
22
- const isTrackingAvailable =
31
+ const isTrackingAvailable: boolean =
23
32
  findArgument(process.argv, "tracking") !== "false";
24
- const maybeRepositorySubdomain = findArgument(process.argv, "repository");
25
- const sendDocs = !findFlag(process.argv, "no-docs");
33
+ const preSelectedRepository: string | undefined = findArgument(
34
+ process.argv,
35
+ "repository"
36
+ );
37
+ const pushDocuments = !findFlag(process.argv, "no-docs");
26
38
 
27
39
  Tracker.get().initialize(
28
40
  process.env.PUBLIC_SM_INIT_SEGMENT_KEY ||
@@ -30,7 +42,14 @@ async function init() {
30
42
  isTrackingAvailable
31
43
  );
32
44
 
33
- void Tracker.get().trackInitStart(maybeRepositorySubdomain);
45
+ void Tracker.get().trackInitStart(preSelectedRepository);
46
+
47
+ // initializing the client with what we have for now.
48
+ const client = new InitClient(
49
+ mode,
50
+ null,
51
+ Prismic.PrismicSharedConfigManager.getAuth()
52
+ );
34
53
 
35
54
  console.log(
36
55
  logs.purple(
@@ -42,48 +61,34 @@ async function init() {
42
61
  validatePkg(cwd);
43
62
 
44
63
  // login
45
- const user = await loginOrBypass(base);
46
- if (!user) throw new Error("The user should be logged in!");
47
-
48
- // If we get the info from the profile we want to identify all the previous events sent or continue in anonymous mode
49
- if (user.profile) {
50
- Tracker.get().identifyUser(user.profile.shortId, user.profile.intercomHash);
51
- }
64
+ const user = await loginOrBypass(client);
52
65
 
66
+ Tracker.get().identifyUser(user.shortId, user.intercomHash);
53
67
  void Tracker.get().trackInitIdentify();
54
68
 
55
- // retrieve tokens for api calls
56
- const config = Prismic.PrismicSharedConfigManager.get();
57
-
58
69
  // detect the framework used by the project
59
70
  const frameworkResult = await detectFramework(cwd);
60
71
 
61
72
  // select the repository used with the project.
62
- const repositoryDomainName = await chooseOrCreateARepository(
73
+ const repository = await chooseOrCreateARepository(
74
+ client,
63
75
  cwd,
64
76
  frameworkResult.value,
65
- config.cookies,
66
- config.base,
67
- maybeRepositorySubdomain
77
+ preSelectedRepository
68
78
  );
69
79
 
70
- Tracker.get().setRepository(repositoryDomainName);
80
+ Tracker.get().setRepository(repository);
81
+ client.updateRepository(repository);
71
82
 
72
83
  const sliceLibPath = lib ? await installLib(cwd, lib, branch) : undefined;
73
84
 
74
- const wasStarter = await sendStarterData(
75
- repositoryDomainName,
76
- config.base,
77
- config.cookies,
78
- sendDocs,
79
- cwd
80
- ); // will be false if no sm.json is found
85
+ const wasStarter = await sendStarterData(client, cwd, pushDocuments); // will be false if no sm.json is found
81
86
 
82
87
  // configure the SM.json file and the json package file of the project..
83
88
  await configureProject(
89
+ client,
84
90
  cwd,
85
- base,
86
- repositoryDomainName,
91
+ repository,
87
92
  frameworkResult,
88
93
  sliceLibPath,
89
94
  isTrackingAvailable
@@ -93,14 +98,18 @@ async function init() {
93
98
  await installRequiredDependencies(cwd, frameworkResult.value, wasStarter);
94
99
 
95
100
  // Ask the user to run slice-machine.
96
- displayFinalMessage(cwd, wasStarter, repositoryDomainName, config.base);
101
+ displayFinalMessage(cwd, wasStarter, repository, client.apisEndpoints.Wroom);
97
102
  }
98
103
 
99
104
  init()
100
105
  .then(() => {
101
106
  process.exit(0);
102
107
  })
103
- .catch((error) => {
108
+ .catch(async (error) => {
104
109
  if (error instanceof Error) logs.writeError(error.message);
105
110
  else console.error(error);
111
+ await Tracker.get().trackInitEndFail(
112
+ Models.Frameworks.none,
113
+ "Failed to initialise Slice Machine."
114
+ );
106
115
  });
@@ -1,26 +1,24 @@
1
1
  import * as inquirer from "inquirer";
2
2
  import Separator from "inquirer/lib/objects/separator";
3
- import { Utils, Models, CONSTS } from "@slicemachine/core";
4
- import * as Prismic from "@slicemachine/core/build/prismic";
3
+ import { Models } from "@slicemachine/core";
5
4
  import * as NodeUtils from "@slicemachine/core/build/node-utils";
6
5
  import { createRepository } from "../utils/create-repo";
7
- import { logs } from "../utils";
6
+ import { validateRepositoryName } from "../utils/validateRepositoryName";
7
+ import { InitClient, logs } from "../utils";
8
8
 
9
9
  export const CREATE_REPO = "$_CREATE_REPO"; // not a valid domain name
10
- const DEFAULT_BASE = CONSTS.DEFAULT_BASE;
11
10
 
12
- export function prettyRepoName(address: URL, value?: string): string {
13
- const repoName = value ? logs.cyan(value) : logs.dim.cyan("repo-name");
14
- return `${logs.cyan.dim(`${address.protocol}//`)}${repoName}${logs.cyan.dim(
15
- `.${address.hostname}`
16
- )}`;
11
+ export function prettyRepoName(address: URL, domain: string): string {
12
+ return `${logs.cyan.dim(`${address.protocol}//`)}${logs.cyan(
13
+ domain
14
+ )}${logs.cyan.dim(`.${address.hostname}`)}`;
17
15
  }
18
16
 
19
17
  export async function promptForRepoDomain(
20
- base: string,
18
+ client: InitClient,
21
19
  defaultValue?: string
22
20
  ): Promise<string> {
23
- const address = new URL(base);
21
+ const address = new URL(client.apisEndpoints.Wroom);
24
22
 
25
23
  logs.writeInfo(
26
24
  "The name acts as a domain/endpoint for your content repo and should be completely unique."
@@ -34,16 +32,9 @@ export async function promptForRepoDomain(
34
32
  type: "input",
35
33
  required: true,
36
34
  default: defaultValue,
37
- transformer: (value: string) =>
38
- prettyRepoName(address, value || defaultValue),
39
- async validate(name: string) {
40
- const result = await Prismic.Communication.validateRepositoryName(
41
- name,
42
- base,
43
- false
44
- );
45
- return result === name || result;
46
- },
35
+ transformer: (value: string | undefined) =>
36
+ prettyRepoName(address, value || defaultValue || "repository"),
37
+ validate: (name: string) => validateRepositoryName(client, name),
47
38
  },
48
39
  ])
49
40
  .then((res) => res.repoDomain);
@@ -122,47 +113,57 @@ export function sortReposForPrompt(
122
113
  }
123
114
 
124
115
  export async function chooseOrCreateARepository(
116
+ client: InitClient,
125
117
  cwd: string,
126
118
  framework: Models.Frameworks,
127
- cookies: string,
128
- base = DEFAULT_BASE,
129
- domain?: string
119
+ preSelectedRepository?: string
130
120
  ): Promise<string> {
131
- const token = Utils.Cookie.parsePrismicAuthToken(cookies);
132
- const repos = await Prismic.Communication.listRepositories(token, base);
133
-
134
- const hasRepo = domain && repos.find((d) => d.domain === domain);
135
- if (hasRepo) return domain;
136
-
137
- if (repos.length === 0) {
138
- const domainName = await promptForRepoDomain(base, domain);
139
- return await createRepository(domainName, framework, cookies, base);
121
+ const repositories: Models.Repository[] = await client.listRepositories();
122
+
123
+ const isPreSelectedValid =
124
+ preSelectedRepository &&
125
+ repositories.find(
126
+ (repository) => repository.domain === preSelectedRepository
127
+ );
128
+ if (isPreSelectedValid) return preSelectedRepository;
129
+
130
+ // No repository to display, ask for a new repository name to create it.
131
+ if (repositories.length === 0) {
132
+ const domainName = await promptForRepoDomain(client, preSelectedRepository);
133
+ await createRepository(client, domainName, framework);
134
+ return domainName;
140
135
  }
141
136
 
142
- const choices = sortReposForPrompt(repos, base, cwd);
143
-
137
+ // prepare the list of repositories to display
138
+ const choices = sortReposForPrompt(
139
+ repositories,
140
+ client.apisEndpoints.Wroom,
141
+ cwd
142
+ );
144
143
  const numberOfDisabledRepos = choices.filter((repo) => {
145
144
  if (repo instanceof Separator) return false;
146
145
  return repo.disabled;
147
146
  }).length;
148
147
 
149
- const res = await inquirer.prompt<{ chosenRepo: string }>([
148
+ // display the list of repositories and wait for the user to choose one.
149
+ const promptResult = await inquirer.prompt<{ chosenRepository: string }>([
150
150
  {
151
151
  type: "list",
152
- name: "chosenRepo",
152
+ name: "chosenRepository",
153
153
  default: 0,
154
154
  required: true,
155
155
  message: "Connect a Prismic Repository or create a new one",
156
156
  choices,
157
157
  pageSize: numberOfDisabledRepos + 2 <= 7 ? 7 : numberOfDisabledRepos + 2,
158
- // loop: false
159
158
  },
160
159
  ]);
161
160
 
162
- if (res.chosenRepo === CREATE_REPO) {
163
- const domainName = await promptForRepoDomain(base, domain);
164
- return await createRepository(domainName, framework, cookies, base);
161
+ // If the user has chosen to create a new repository.
162
+ if (promptResult.chosenRepository === CREATE_REPO) {
163
+ const domainName = await promptForRepoDomain(client, preSelectedRepository);
164
+ await createRepository(client, domainName, framework);
165
+ return domainName;
165
166
  }
166
167
 
167
- return res.chosenRepo;
168
+ return promptResult.chosenRepository;
168
169
  }
@@ -3,16 +3,14 @@ import type { Models } from "@slicemachine/core";
3
3
  import * as Prismic from "@slicemachine/core/build/prismic";
4
4
  import * as NodeUtils from "@slicemachine/core/build/node-utils";
5
5
  import { FrameworkResult } from "./detect-framework";
6
- import { logs } from "../utils";
6
+ import { InitClient, logs } from "../utils";
7
7
  import Tracker from "../utils/tracker";
8
8
 
9
- type Base = Prismic.Endpoints.Base;
10
-
11
9
  const defaultSliceMachineVersion = "0.0.41";
12
10
 
13
11
  export async function configureProject(
12
+ client: InitClient,
14
13
  cwd: string,
15
- base: Base,
16
14
  repositoryDomainName: string,
17
15
  framework: FrameworkResult,
18
16
  sliceLibPath: string[] = [],
@@ -45,7 +43,7 @@ export async function configureProject(
45
43
  ? manifest.content
46
44
  : { _latest: sliceMachineVersionInstalled }),
47
45
  apiEndpoint: Prismic.Endpoints.buildRepositoryEndpoint(
48
- base,
46
+ client.apisEndpoints.Wroom,
49
47
  repositoryDomainName
50
48
  ),
51
49
  libraries: [...libs, ...sliceLibPath], // odd case here for staters
@@ -70,10 +68,14 @@ export async function configureProject(
70
68
  // add slicemachine script to package.json.
71
69
  NodeUtils.addJsonPackageSmScript(cwd);
72
70
 
73
- await Tracker.get().trackInitDone(framework.value);
71
+ await Tracker.get().trackInitEndSuccess(framework.value);
74
72
 
75
73
  spinner.succeed("Project configured! Ready to start");
76
- } catch {
74
+ } catch (error) {
75
+ await Tracker.get().trackInitEndFail(
76
+ framework.value,
77
+ "Failed to configure Slice Machine"
78
+ );
77
79
  spinner.fail("Failed to configure Slice Machine");
78
80
  process.exit(-1);
79
81
  }
@@ -2,6 +2,7 @@ import { Models } from "@slicemachine/core";
2
2
  import * as NodeUtils from "@slicemachine/core/build/node-utils";
3
3
  import * as inquirer from "inquirer";
4
4
  import { logs } from "../utils";
5
+ import Tracker from "../utils/tracker";
5
6
 
6
7
  export type FrameworkResult = {
7
8
  value: Models.Frameworks;
@@ -80,7 +81,10 @@ export async function detectFramework(cwd: string): Promise<FrameworkResult> {
80
81
  } else {
81
82
  console.log(failMessage);
82
83
  }
83
-
84
+ await Tracker.get().trackInitEndFail(
85
+ Models.Frameworks.none,
86
+ "Framework not detected"
87
+ );
84
88
  process.exit(1);
85
89
  }
86
90
  }
@@ -107,6 +107,10 @@ export async function installLib(
107
107
  if (error instanceof Error) {
108
108
  console.error(error.message);
109
109
  }
110
+ await Tracker.get().trackInitEndFail(
111
+ Models.Frameworks.none,
112
+ "Failed to install ${libGithubPath} library"
113
+ );
110
114
  process.exit(-1);
111
115
  }
112
116
  }
@@ -1,21 +1,25 @@
1
1
  import { Models } from "@slicemachine/core";
2
- import { validateSessionAndGetProfile } from "../utils/communication";
3
- import { logs, Auth } from "../utils";
2
+ import { PrismicSharedConfigManager } from "@slicemachine/core/build/prismic";
3
+ import { logs, Auth, InitClient } from "../utils";
4
+
5
+ export async function loginOrBypass(
6
+ client: InitClient
7
+ ): Promise<Models.UserProfile> {
8
+ const user: Models.UserProfile | null = await client
9
+ .profile()
10
+ .catch(() => null);
4
11
 
5
- export async function loginOrBypass(base: string): Promise<{
6
- info: Models.UserInfo;
7
- profile: Models.UserProfile | null;
8
- } | null> {
9
- const user = await validateSessionAndGetProfile(base).catch((err) =>
10
- console.log(err)
11
- );
12
12
  if (user) {
13
- const email = user.info.email;
13
+ const email = user.email;
14
14
  logs.writeCheck(`Logged in as ${logs.bold(email)}`);
15
15
  return user;
16
- } else {
17
- await Auth.login(base);
18
- const user = await validateSessionAndGetProfile(base);
19
- return user;
20
16
  }
17
+
18
+ await Auth.login(client);
19
+
20
+ // update token used to make calls.
21
+ client.updateAuthenticationToken(PrismicSharedConfigManager.getAuth());
22
+
23
+ const userAfterLogin: Models.UserProfile = await client.profile();
24
+ return userAfterLogin;
21
25
  }
@@ -1,43 +1,31 @@
1
- import { parsePrismicAuthToken } from "@slicemachine/core/build/utils/cookie";
2
1
  import { retrieveManifest, Files } from "@slicemachine/core/build/node-utils";
3
2
  import path from "path";
4
- import { sendSlicesFromStarter } from "./starters/slices";
5
- import { sendCustomTypesFromStarter } from "./starters/custom-types";
6
- import { sendDocumentsFromStarter } from "./starters/documents";
7
3
  import fs from "fs";
4
+ import { sendSlices } from "./starters/slices";
5
+ import { sendCustomTypes } from "./starters/custom-types";
6
+ import { sendDocuments } from "./starters/documents";
7
+ import { InitClient } from "../utils";
8
8
 
9
9
  export async function sendStarterData(
10
- repository: string,
11
- base: string,
12
- cookies: string,
13
- sendDocs = true,
14
- cwd: string
15
- ): Promise<boolean> {
16
- const smJson = retrieveManifest(cwd);
17
- const pathToDocuments = path.join(cwd, "documents");
18
- const hasDocuments = Files.exists(pathToDocuments);
10
+ client: InitClient,
11
+ cwd: string,
12
+ pushDocuments = true
13
+ ) {
14
+ const manifest = retrieveManifest(cwd);
15
+ const documentsPath = path.join(cwd, "documents");
16
+ const hasDocuments = Files.exists(documentsPath);
19
17
 
20
- if (smJson.exists === false || hasDocuments === false)
18
+ if (manifest.exists === false || hasDocuments === false)
21
19
  return Promise.resolve(false);
22
20
 
23
- const authTokenFromCookie = parsePrismicAuthToken(cookies);
21
+ if (manifest.content) await sendSlices(client, cwd, manifest.content);
22
+ await sendCustomTypes(client, cwd);
24
23
 
25
- if (smJson.content && smJson.content.libraries) {
26
- await sendSlicesFromStarter(
27
- base,
28
- repository,
29
- authTokenFromCookie,
30
- smJson.content.libraries,
31
- cwd
32
- );
33
- }
34
-
35
- await sendCustomTypesFromStarter(repository, authTokenFromCookie, base, cwd);
36
-
37
- if (sendDocs === false) {
38
- fs.rmSync(pathToDocuments, { recursive: true, force: true });
24
+ // If the user choose not to push documents, we still delete the documents folder.
25
+ if (!pushDocuments) {
26
+ fs.rmSync(documentsPath, { recursive: true, force: true });
39
27
  return Promise.resolve(true);
40
28
  }
41
29
 
42
- return sendDocumentsFromStarter(repository, cookies, base, cwd);
30
+ return sendDocuments(client, cwd);
43
31
  }
@@ -1,15 +1,11 @@
1
1
  import { CustomType } from "@prismicio/types-internal/lib/customtypes";
2
2
  import { Files, CustomTypesPaths } from "@slicemachine/core/build/node-utils";
3
3
  import { isLeft } from "fp-ts/lib/Either";
4
- import {
5
- getRemoteCustomTypeIds,
6
- sendManyCustomTypesToPrismic,
7
- } from "./communication";
8
4
  import { promptToPushCustomTypes } from "./prompts";
9
- import { getEndpointsFromBase } from "./endpoints";
10
- import { logs } from "../../utils";
5
+ import { InitClient, logs } from "../../utils";
6
+ import { ClientError } from "@slicemachine/client";
11
7
 
12
- export function readCustomTypes(cwd: string): Array<CustomType> {
8
+ export function readLocalCustomTypes(cwd: string): Array<CustomType> {
13
9
  const customTypePaths = CustomTypesPaths(cwd);
14
10
  const dir = customTypePaths.value();
15
11
 
@@ -40,23 +36,15 @@ export function readCustomTypes(cwd: string): Array<CustomType> {
40
36
  return files;
41
37
  }
42
38
 
43
- export async function sendCustomTypesFromStarter(
44
- repository: string,
45
- authorization: string,
46
- base: string,
47
- cwd: string
48
- ) {
49
- const customTypeApiEndpoint = getEndpointsFromBase(base).Models;
39
+ export async function sendCustomTypes(client: InitClient, cwd: string) {
40
+ const localCustomTypes = readLocalCustomTypes(cwd);
50
41
 
51
- const customTypes = readCustomTypes(cwd);
42
+ // nothing to push
43
+ if (localCustomTypes.length === 0) return Promise.resolve(false);
52
44
 
53
- if (customTypes.length === 0) return Promise.resolve(false);
54
-
55
- const remoteCustomTypeIds = await getRemoteCustomTypeIds(
56
- customTypeApiEndpoint,
57
- repository,
58
- authorization
59
- );
45
+ const remoteCustomTypeIds = await client
46
+ .getCustomTypes()
47
+ .then((customTypes) => customTypes.map((customType) => customType.id));
60
48
 
61
49
  if (remoteCustomTypeIds.length) {
62
50
  const shouldPush = await promptToPushCustomTypes();
@@ -68,15 +56,26 @@ export async function sendCustomTypesFromStarter(
68
56
  );
69
57
  spinner.start();
70
58
 
71
- await sendManyCustomTypesToPrismic(
72
- repository,
73
- authorization,
74
- customTypeApiEndpoint,
75
- remoteCustomTypeIds,
76
- customTypes
77
- );
59
+ await Promise.all(
60
+ localCustomTypes.map(async (customType) => {
61
+ const promise = remoteCustomTypeIds.includes(customType.id)
62
+ ? client.updateCustomType(customType)
63
+ : client.insertCustomType(customType);
64
+
65
+ return promise.catch((error: ClientError) => {
66
+ logs.writeError(
67
+ `Sending custom type ${customType.id} - ${error.message}`
68
+ );
69
+
70
+ // throwing the error again to stop the Promise.all
71
+ throw error;
72
+ });
73
+ })
74
+ ).catch(() => {
75
+ // the error about the custom type that failed to be pushed should be in the terminal already.
76
+ process.exit(1);
77
+ });
78
78
 
79
79
  spinner.succeed();
80
-
81
80
  return Promise.resolve(true);
82
81
  }