@slicemachine/init 1.1.4 → 1.1.5-alpha.11

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,4 +1,5 @@
1
- import { Utils } from "@slicemachine/core";
1
+ import { Models } from "@slicemachine/core";
2
+ import * as NodeUtils from "@slicemachine/core/build/node-utils";
2
3
  import tmp from "tmp";
3
4
  import AdmZip from "adm-zip";
4
5
  import fsExtra from "fs-extra";
@@ -8,13 +9,10 @@ import fs from "fs";
8
9
  import path from "path";
9
10
  import { getOrElseW } from "fp-ts/Either";
10
11
  import { PackageManager, Dependencies } from "../utils/PackageManager";
11
- import { PackageJsonHelper } from "@slicemachine/core/build/src/utils/PackageJson";
12
- import {
13
- Manifest,
14
- ManifestHelper,
15
- } from "@slicemachine/core/build/src/models/Manifest";
16
- import Files from "@slicemachine/core/build/src/utils/files";
17
12
  import Tracker from "../utils/tracker";
13
+ import { logs } from "../utils";
14
+
15
+ const { PackageJsonHelper } = NodeUtils;
18
16
 
19
17
  const downloadFile = async (reqUrl: string): Promise<string> => {
20
18
  const res = await axios.get<Buffer>(reqUrl, { responseType: "arraybuffer" });
@@ -40,7 +38,7 @@ export async function installLib(
40
38
  libGithubPath: string,
41
39
  branch = "HEAD"
42
40
  ): Promise<string[] | undefined> {
43
- const spinner = Utils.spinner(
41
+ const spinner = logs.spinner(
44
42
  `Installing the ${libGithubPath} lib in your project...`
45
43
  );
46
44
 
@@ -77,22 +75,22 @@ export async function installLib(
77
75
  if (dependencies) await pkgManager.install(dependencies);
78
76
 
79
77
  // generate meta file
80
- Files.write(path.join(libDestinationFolder, "meta.json"), {
78
+ NodeUtils.Files.write(path.join(libDestinationFolder, "meta.json"), {
81
79
  name: pkgJson.name,
82
80
  });
83
81
 
84
82
  // retrieve all slices lib paths
85
- const manifest = Files.readEntity<Error | Manifest>(
83
+ const manifest = NodeUtils.Files.readEntity<Error | Models.Manifest>(
86
84
  path.join(projectPath, "sm.json"),
87
85
  (payload: unknown) => {
88
86
  return getOrElseW(
89
87
  () => new Error(`Unable to parse sm.json from lib ${libGithubPath}`)
90
- )(Manifest.decode(payload));
88
+ )(Models.Manifest.decode(payload));
91
89
  }
92
90
  );
93
91
  if (manifest instanceof Error) throw manifest;
94
92
 
95
- const localLibs = ManifestHelper.localLibraries(manifest).map(
93
+ const localLibs = Models.ManifestHelper.localLibraries(manifest).map(
96
94
  ({ path }) => {
97
95
  return `~/${name}/${path.replace("src/", "")}`;
98
96
  }
@@ -1,6 +1,7 @@
1
1
  import path from "path";
2
- import { execCommand } from "../utils";
3
- import { Utils, FileSystem, Models } from "@slicemachine/core";
2
+ import { execCommand, logs } from "../utils";
3
+ import { CONSTS, Models } from "@slicemachine/core";
4
+ import * as NodeUtils from "@slicemachine/core/build/node-utils";
4
5
 
5
6
  const {
6
7
  PRISMIC_CLIENT,
@@ -12,7 +13,7 @@ const {
12
13
  SLICE_SIMULATOR_REACT,
13
14
  SLICE_SIMULATOR_VUE,
14
15
  PRISMIC_HELPERS,
15
- } = Utils.CONSTS;
16
+ } = CONSTS;
16
17
 
17
18
  function depsForFramework(framework: Models.Frameworks): string {
18
19
  switch (framework) {
@@ -35,13 +36,13 @@ export async function installRequiredDependencies(
35
36
  cwd: string,
36
37
  framework: Models.Frameworks
37
38
  ): Promise<void> {
38
- const yarnLock = Utils.Files.exists(FileSystem.YarnLockPath(cwd));
39
+ const yarnLock = NodeUtils.Files.exists(NodeUtils.YarnLockPath(cwd));
39
40
  const installDevDependencyCommand = yarnLock
40
41
  ? "yarn add -D"
41
42
  : "npm install --save-dev";
42
43
  const installDependencyCommand = yarnLock ? "yarn add" : "npm install --save";
43
44
 
44
- const spinner = Utils.spinner("Downloading Slice Machine");
45
+ const spinner = logs.spinner("Downloading Slice Machine");
45
46
  spinner.start();
46
47
 
47
48
  const { stderr } = await execCommand(
@@ -52,10 +53,10 @@ export async function installRequiredDependencies(
52
53
  if (deps) await execCommand(`${installDependencyCommand} ${deps}`);
53
54
 
54
55
  const pathToPkg = path.join(
55
- FileSystem.PackagePaths(cwd).value(),
56
+ NodeUtils.PackagePaths(cwd).value(),
56
57
  SM_PACKAGE_NAME
57
58
  );
58
- const isPackageInstalled = Utils.Files.exists(pathToPkg);
59
+ const isPackageInstalled = NodeUtils.Files.exists(pathToPkg);
59
60
 
60
61
  if (isPackageInstalled || !stderr.length) {
61
62
  spinner.succeed("Slice Machine was installed successfully");
@@ -63,7 +64,7 @@ export async function installRequiredDependencies(
63
64
  }
64
65
 
65
66
  spinner.fail();
66
- Utils.writeWarning(
67
+ logs.writeWarning(
67
68
  `could not install ${SM_PACKAGE_NAME}. Please do it manually!`
68
69
  );
69
70
  }
@@ -1,5 +1,6 @@
1
- import { Utils, Auth, Models } from "@slicemachine/core";
1
+ import { Models } from "@slicemachine/core";
2
2
  import { validateSessionAndGetProfile } from "../utils/communication";
3
+ import { logs, Auth } from "../utils";
3
4
 
4
5
  export async function loginOrBypass(base: string): Promise<{
5
6
  info: Models.UserInfo;
@@ -10,7 +11,7 @@ export async function loginOrBypass(base: string): Promise<{
10
11
  );
11
12
  if (user) {
12
13
  const email = user.info.email;
13
- Utils.writeCheck(`Logged in as ${Utils.bold(email)}`);
14
+ logs.writeCheck(`Logged in as ${logs.bold(email)}`);
14
15
  return user;
15
16
  } else {
16
17
  await Auth.login(base);
@@ -1,13 +1,14 @@
1
- import { FileSystem, Utils } from "@slicemachine/core";
1
+ import * as NodeUtils from "@slicemachine/core/build/node-utils";
2
+ import { logs } from "../utils";
2
3
 
3
4
  export function validatePkg(cwd: string): void {
4
- const jsonPackage = FileSystem.retrieveJsonPackage(cwd);
5
+ const jsonPackage = NodeUtils.retrieveJsonPackage(cwd);
5
6
  if (!jsonPackage.exists) {
6
- Utils.writeError(`package.json not found. Are you in the right folder?`);
7
+ logs.writeError(`package.json not found. Are you in the right folder?`);
7
8
  return process.exit(-1);
8
9
  }
9
10
  if (!jsonPackage.content) {
10
- Utils.writeError(`could not parse package.json.`);
11
+ logs.writeError(`could not parse package.json.`);
11
12
  return process.exit(-1);
12
13
  }
13
14
  }
@@ -1,4 +1,4 @@
1
- import { Utils, FileSystem } from "@slicemachine/core";
1
+ import * as NodeUtils from "@slicemachine/core/build/node-utils";
2
2
  import { execCommand } from "../utils";
3
3
 
4
4
  export type Dependency = string | { name: string; version: string };
@@ -32,7 +32,7 @@ export interface PackageManager {
32
32
 
33
33
  export const PackageManager = {
34
34
  get(cwd: string): PackageManager {
35
- if (Utils.Files.exists(FileSystem.YarnLockPath(cwd))) {
35
+ if (NodeUtils.Files.exists(NodeUtils.YarnLockPath(cwd))) {
36
36
  return Yarn;
37
37
  }
38
38
  return Npm;
@@ -0,0 +1,164 @@
1
+ import * as hapi from "@hapi/hapi";
2
+ import open from "open";
3
+ import * as logs from "../logs";
4
+ import { Utils, CONSTS } from "@slicemachine/core";
5
+ import { PrismicSharedConfigManager } from "@slicemachine/core/build/prismic";
6
+
7
+ const { Cookie } = Utils;
8
+ const { DEFAULT_BASE, DEFAULT_SERVER_PORT } = CONSTS;
9
+
10
+ const { bold, underline, spinner, writeError } = logs;
11
+
12
+ export type HandlerData = { email: string; cookies: ReadonlyArray<string> };
13
+
14
+ export const isHandlerData = (
15
+ data: string | Record<string, unknown>
16
+ ): data is HandlerData => {
17
+ if (typeof data != "object") return false;
18
+
19
+ const { email, cookies } = data as Partial<HandlerData>;
20
+ return (
21
+ Boolean(email && cookies) &&
22
+ Array.isArray(cookies) &&
23
+ !cookies.some((c: unknown) => typeof c !== "string")
24
+ );
25
+ };
26
+
27
+ const Routes = {
28
+ authentication:
29
+ (server: hapi.Server) =>
30
+ (
31
+ onSuccess: (data: HandlerData) => void,
32
+ onFail: () => void
33
+ ): hapi.ServerRoute => ({
34
+ method: "POST",
35
+ path: "/",
36
+ handler: authenticationHandler(server)(onSuccess, onFail),
37
+ }),
38
+
39
+ notFound: {
40
+ method: ["GET", "POST"],
41
+ path: "/{any*}",
42
+ handler: (
43
+ request: hapi.Request,
44
+ h: hapi.ResponseToolkit
45
+ ): hapi.ResponseObject => {
46
+ return h
47
+ .response(`not found: [${request.method}]: ${request.url.toString()}`)
48
+ .code(404);
49
+ },
50
+ },
51
+ };
52
+
53
+ export function validatePayload(
54
+ payload: Buffer | string | Record<string, unknown>
55
+ ): HandlerData | null {
56
+ if (Buffer.isBuffer(payload)) return null;
57
+ return isHandlerData(payload) ? payload : null;
58
+ }
59
+
60
+ const authenticationHandler =
61
+ (server: hapi.Server) =>
62
+ (onSuccess: (data: HandlerData) => void, onFail: () => void) => {
63
+ return (request: hapi.Request, h: hapi.ResponseToolkit) => {
64
+ try {
65
+ const data: HandlerData | null = validatePayload(
66
+ request.payload as Buffer | string | Record<string, unknown>
67
+ ); // type coming from the lib
68
+
69
+ if (!data) {
70
+ onFail();
71
+ h.response("Error with cookies").code(400);
72
+ throw new Error(
73
+ "It seems the server didn't respond properly, please contact us."
74
+ );
75
+ }
76
+ onSuccess(data);
77
+ return h.response(data).code(200);
78
+ } finally {
79
+ void server.stop({ timeout: 10000 });
80
+ }
81
+ };
82
+ };
83
+
84
+ function buildServer(base: string, port: number, host: string): hapi.Server {
85
+ const server = hapi.server({
86
+ port,
87
+ host,
88
+ routes: {
89
+ cors: {
90
+ origin: [base],
91
+ headers: ["Origin", "X-Requested-With", "Content-Type", "Accept"],
92
+ },
93
+ },
94
+ });
95
+ return server;
96
+ }
97
+
98
+ export function askSingleChar(title: string): Promise<string> {
99
+ return new Promise((resolve) => {
100
+ process.stdout.write(title);
101
+ const rawMode: boolean = process.stdin.isRaw;
102
+ if (process.stdin.setRawMode) process.stdin.setRawMode(true);
103
+
104
+ function handler(key: Buffer) {
105
+ const response: string = key.toString("utf-8");
106
+ if (process.stdin.setRawMode) process.stdin.setRawMode(Boolean(rawMode));
107
+ process.stdin.removeListener("data", handler);
108
+ resolve(response);
109
+ }
110
+
111
+ process.stdin.on("data", handler);
112
+ });
113
+ }
114
+
115
+ export async function startServerAndOpenBrowser(
116
+ url: string,
117
+ action: "login" | "signup",
118
+ base: string = DEFAULT_BASE,
119
+ port: number = DEFAULT_SERVER_PORT
120
+ ): Promise<{
121
+ onLoginFail: () => void;
122
+ }> {
123
+ const confirmation = await askSingleChar(
124
+ `>> Press any key to open the browser to ${action} or q to exit:`
125
+ );
126
+ if (confirmation === "q" || confirmation === "\u0003")
127
+ return process.exit(-1);
128
+
129
+ const s = spinner("Waiting for the browser response");
130
+
131
+ const onLoginFail = () => {
132
+ s.stop();
133
+ writeError(`We failed to log you into your Prismic account`);
134
+ console.log(`Run ${bold("npx slicemachine init")} again!`);
135
+ process.exit(-1);
136
+ };
137
+
138
+ function onSuccess(data: HandlerData) {
139
+ s.succeed(`Logged in as ${bold(data.email)}`).stop();
140
+ PrismicSharedConfigManager.setProperties({
141
+ cookies: Cookie.serializeCookies(data.cookies),
142
+ base,
143
+ });
144
+ }
145
+
146
+ function onFail(): void {
147
+ onLoginFail();
148
+ }
149
+
150
+ const server = buildServer(base, port, "localhost");
151
+ server.route([
152
+ Routes.authentication(server)(onSuccess, onFail),
153
+ Routes.notFound,
154
+ ]);
155
+
156
+ return server.start().then(() => {
157
+ console.log("\nOpening browser to " + underline(url));
158
+ s.start();
159
+ void open(url);
160
+ return {
161
+ onLoginFail,
162
+ };
163
+ });
164
+ }
@@ -0,0 +1,63 @@
1
+ import { Utils, Models } from "@slicemachine/core";
2
+ import { startServerAndOpenBrowser } from "./helpers";
3
+ import {
4
+ Communication,
5
+ Endpoints,
6
+ PrismicSharedConfigManager,
7
+ } from "@slicemachine/core/build/prismic";
8
+
9
+ async function startAuth({
10
+ base,
11
+ url,
12
+ action,
13
+ }: {
14
+ base: string;
15
+ url: string;
16
+ action: "signup" | "login";
17
+ }): Promise<void> {
18
+ const { onLoginFail } = await startServerAndOpenBrowser(url, action, base);
19
+ try {
20
+ // We wait 3 minutes before timeout
21
+ await Utils.Poll.startPolling<Models.UserInfo | null, Models.UserInfo>(
22
+ () => Auth.validateSession(base),
23
+ (user): user is Models.UserInfo => !!user,
24
+ 3000,
25
+ 60
26
+ );
27
+ return;
28
+ } catch (e) {
29
+ onLoginFail();
30
+ }
31
+ }
32
+
33
+ export const Auth = {
34
+ login: async (base: string): Promise<void> => {
35
+ const endpoints = Endpoints.buildEndpoints(base);
36
+ return startAuth({
37
+ base,
38
+ url: endpoints.Dashboard.cliLogin,
39
+ action: "login",
40
+ });
41
+ },
42
+ signup: async (base: string): Promise<void> => {
43
+ const endpoints = Endpoints.buildEndpoints(base);
44
+ return startAuth({
45
+ base,
46
+ url: endpoints.Dashboard.cliSignup,
47
+ action: "signup",
48
+ });
49
+ },
50
+ logout: (): void => PrismicSharedConfigManager.remove(),
51
+ validateSession: async (
52
+ requiredBase: string
53
+ ): Promise<Models.UserInfo | null> => {
54
+ const config = PrismicSharedConfigManager.get();
55
+
56
+ if (!config.cookies.length) return Promise.resolve(null); // default config, logged out.
57
+ if (requiredBase != config.base) return Promise.resolve(null); // not the same base so it doesn't count.
58
+
59
+ return Communication.validateSession(config.cookies, requiredBase).catch(
60
+ () => null
61
+ );
62
+ },
63
+ };
@@ -2,16 +2,17 @@ import axios from "axios";
2
2
  import * as t from "io-ts";
3
3
  import { pipe } from "fp-ts/function";
4
4
  import { fold } from "fp-ts/Either";
5
- import { Utils, Models, Communication, FileSystem } from "@slicemachine/core";
5
+ import { Utils, Models, CONSTS } from "@slicemachine/core";
6
+ import * as Prismic from "@slicemachine/core/build/prismic";
6
7
 
7
8
  export async function getUserProfile(
8
9
  cookies: string,
9
- base = Utils.CONSTS.DEFAULT_BASE
10
+ base = CONSTS.DEFAULT_BASE
10
11
  ): Promise<Models.UserProfile> {
11
12
  const userServiceBase =
12
- Utils.CONSTS.DEFAULT_BASE === base
13
- ? Utils.CONSTS.USER_SERVICE_BASE
14
- : Utils.CONSTS.USER_SERVICE_STAGING_BASE;
13
+ CONSTS.DEFAULT_BASE === base
14
+ ? CONSTS.USER_SERVICE_BASE
15
+ : CONSTS.USER_SERVICE_STAGING_BASE;
15
16
 
16
17
  // note the auth server also provides a userId
17
18
  const url = new URL(userServiceBase);
@@ -40,23 +41,26 @@ export async function getUserProfile(
40
41
  }
41
42
 
42
43
  export async function validateSessionAndGetProfile(
43
- base = Utils.CONSTS.DEFAULT_BASE
44
+ base = CONSTS.DEFAULT_BASE
44
45
  ): Promise<{
45
46
  info: Models.UserInfo;
46
47
  profile: Models.UserProfile | null;
47
48
  } | null> {
48
- const config = FileSystem.PrismicSharedConfigManager.get();
49
+ const config = Prismic.PrismicSharedConfigManager.get();
49
50
 
50
51
  if (!config.cookies.length) return Promise.resolve(null); // default config, logged out.
51
52
  if (base != config.base) return Promise.resolve(null); // not the same base so it doesn't
52
53
 
53
54
  try {
54
- const info = await Communication.validateSession(config.cookies, base);
55
+ const info = await Prismic.Communication.validateSession(
56
+ config.cookies,
57
+ base
58
+ );
55
59
  const profile = await getUserProfile(config.cookies, base).catch(
56
60
  () => null
57
61
  );
58
62
  if (profile?.shortId) {
59
- FileSystem.PrismicSharedConfigManager.setProperties({
63
+ Prismic.PrismicSharedConfigManager.setProperties({
60
64
  shortId: profile.shortId,
61
65
  });
62
66
  }
@@ -1,5 +1,6 @@
1
- import { Communication, Utils } from "@slicemachine/core";
2
1
  import type { Models } from "@slicemachine/core";
2
+ import * as logs from "./logs";
3
+ import * as Prismic from "@slicemachine/core/build/prismic";
3
4
 
4
5
  export function createRepository(
5
6
  domain: string,
@@ -7,10 +8,15 @@ export function createRepository(
7
8
  cookies: string,
8
9
  base: string
9
10
  ): Promise<string> {
10
- const spinner = Utils.spinner("Creating Prismic Repository");
11
+ const spinner = logs.spinner("Creating Prismic Repository");
11
12
  spinner.start();
12
13
 
13
- return Communication.createRepository(domain, cookies, framework, base)
14
+ return Prismic.Communication.createRepository(
15
+ domain,
16
+ cookies,
17
+ framework,
18
+ base
19
+ )
14
20
  .then((res) => {
15
21
  const addressUrl = new URL(base);
16
22
  const repoDomainName = res.data.domain || domain;
@@ -23,10 +29,10 @@ export function createRepository(
23
29
  .catch((error: Error) => {
24
30
  spinner.fail(`Error creating repository ${domain}`);
25
31
  if (error.message) {
26
- Utils.writeError(error.message);
32
+ logs.writeError(error.message);
27
33
  }
28
- Utils.writeError(`We failed to create you new prismic repository`);
29
- console.log(`Run ${Utils.bold("npx @slicemachine/init")} again!`);
34
+ logs.writeError(`We failed to create you new prismic repository`);
35
+ console.log(`Run ${logs.bold("npx @slicemachine/init")} again!`);
30
36
  process.exit(-1);
31
37
  });
32
38
  }
@@ -1,5 +1,7 @@
1
1
  import util from "util";
2
2
  import { exec } from "child_process";
3
+ export * as logs from "./logs";
4
+ export { Auth } from "./auth";
3
5
 
4
6
  export function findArgument(args: string[], name: string): string | undefined {
5
7
  const flagIndex: number = args.indexOf(`--${name}`);
@@ -0,0 +1,28 @@
1
+ import chalk from "chalk";
2
+ import ora from "ora";
3
+
4
+ export const purple = chalk.hex("8c76fc");
5
+ export const error = chalk.hex("FF6868");
6
+ export const warning = chalk.hex("F3AD38");
7
+ export const underline = chalk.underline;
8
+ export const bold = chalk.bold;
9
+ export const dim = chalk.dim;
10
+ export const cyan = chalk.cyan;
11
+ export const yellow = chalk.yellow;
12
+ export const white = chalk.white;
13
+
14
+ export const spinner = ora;
15
+
16
+ export const writeError = (msg: string, prefix = "Error!"): void =>
17
+ console.error(`${error(prefix)} ${msg}`);
18
+
19
+ export const writeWarning = (msg: string, prefix = "Warning!"): void =>
20
+ console.warn(`${warning(prefix)} ${msg}`);
21
+
22
+ export const writeCheck = (msg: string): void => {
23
+ ora().succeed(msg); // using the same check as Ora for coherence
24
+ };
25
+
26
+ export const writeInfo = (msg: string): void => {
27
+ console.log(`${yellow("ℹ")} ${dim(msg)}`);
28
+ };
@@ -1,10 +1,11 @@
1
1
  import ServerAnalytics from "analytics-node";
2
2
  import { v4 as uuidv4 } from "uuid";
3
- import { Frameworks } from "@slicemachine/core/build/src/models";
3
+ import { Models } from "@slicemachine/core";
4
4
 
5
5
  export enum EventType {
6
6
  DownloadLibrary = "SliceMachine Download Library",
7
7
  InitStart = "SliceMachine Init Start",
8
+ InitIdentify = "SliceMachine Init Identify",
8
9
  InitDone = "SliceMachine Init Done",
9
10
  }
10
11
 
@@ -90,11 +91,15 @@ export class InitTracker {
90
91
  this._trackEvent(EventType.DownloadLibrary, { library });
91
92
  }
92
93
 
93
- trackInitStart(): void {
94
- this._trackEvent(EventType.InitStart);
94
+ trackInitIdentify(repoDomain: string | undefined): void {
95
+ this._trackEvent(EventType.InitIdentify, { repo: repoDomain });
95
96
  }
96
97
 
97
- trackInitDone(framework: Frameworks, repoDomain: string): void {
98
+ trackInitStart(repoDomain: string | undefined): void {
99
+ this._trackEvent(EventType.InitStart, { repo: repoDomain });
100
+ }
101
+
102
+ trackInitDone(framework: Models.Frameworks, repoDomain: string): void {
98
103
  this._trackEvent(EventType.InitDone, { framework, repo: repoDomain });
99
104
  }
100
105
  }