@slicemachine/init 1.1.10-alpha.1 → 1.1.10-alpha.10

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/build/index.js CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  'use strict';
4
4
 
5
- const core = require('@slicemachine/core');
5
+ const client = require('@slicemachine/client');
6
6
  const Prismic = require('@slicemachine/core/build/prismic');
7
7
  const ServerAnalytics = require('analytics-node');
8
8
  const uuid = require('uuid');
@@ -11,27 +11,24 @@ const util = require('util');
11
11
  const child_process = require('child_process');
12
12
  const chalk = require('chalk');
13
13
  const ora = require('ora');
14
+ const core = require('@slicemachine/core');
14
15
  const hapi = require('@hapi/hapi');
15
16
  const open = require('open');
17
+ const t = require('io-ts');
18
+ const fs = require('fs');
16
19
  const NodeUtils = require('@slicemachine/core/build/node-utils');
17
20
  const inquirer = require('inquirer');
18
21
  const Separator = require('inquirer/lib/objects/separator');
19
- const axios = require('axios');
20
- const _function = require('fp-ts/function');
21
- const Either = require('fp-ts/Either');
22
22
  const tmp = require('tmp');
23
23
  const AdmZip = require('adm-zip');
24
24
  const fsExtra = require('fs-extra');
25
- const fs = require('fs');
26
- const cookie = require('@slicemachine/core/build/utils/cookie');
27
- const Libraries = require('@slicemachine/core/build/libraries');
25
+ const axios = require('axios');
26
+ const Either = require('fp-ts/Either');
28
27
  const models = require('@slicemachine/core/build/models');
29
- const mime = require('mime');
30
- const snakeCase = require('lodash.snakecase');
31
- const FormData = require('form-data');
32
- const uniqid = require('uniqid');
28
+ const Libraries = require('@slicemachine/core/build/libraries');
33
29
  const customtypes = require('@prismicio/types-internal/lib/customtypes');
34
30
  const Either$1 = require('fp-ts/lib/Either');
31
+ const SharedConfig = require('@slicemachine/core/build/prismic/SharedConfig');
35
32
 
36
33
  function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
37
34
 
@@ -62,20 +59,17 @@ const chalk__default = /*#__PURE__*/_interopDefaultLegacy(chalk);
62
59
  const ora__default = /*#__PURE__*/_interopDefaultLegacy(ora);
63
60
  const hapi__namespace = /*#__PURE__*/_interopNamespace(hapi);
64
61
  const open__default = /*#__PURE__*/_interopDefaultLegacy(open);
62
+ const t__namespace = /*#__PURE__*/_interopNamespace(t);
63
+ const fs__default = /*#__PURE__*/_interopDefaultLegacy(fs);
65
64
  const NodeUtils__namespace = /*#__PURE__*/_interopNamespace(NodeUtils);
66
65
  const inquirer__namespace = /*#__PURE__*/_interopNamespace(inquirer);
67
66
  const inquirer__default = /*#__PURE__*/_interopDefaultLegacy(inquirer);
68
67
  const Separator__default = /*#__PURE__*/_interopDefaultLegacy(Separator);
69
- const axios__default = /*#__PURE__*/_interopDefaultLegacy(axios);
70
68
  const tmp__default = /*#__PURE__*/_interopDefaultLegacy(tmp);
71
69
  const AdmZip__default = /*#__PURE__*/_interopDefaultLegacy(AdmZip);
72
70
  const fsExtra__default = /*#__PURE__*/_interopDefaultLegacy(fsExtra);
73
- const fs__default = /*#__PURE__*/_interopDefaultLegacy(fs);
71
+ const axios__default = /*#__PURE__*/_interopDefaultLegacy(axios);
74
72
  const Libraries__namespace = /*#__PURE__*/_interopNamespace(Libraries);
75
- const mime__default = /*#__PURE__*/_interopDefaultLegacy(mime);
76
- const snakeCase__default = /*#__PURE__*/_interopDefaultLegacy(snakeCase);
77
- const FormData__default = /*#__PURE__*/_interopDefaultLegacy(FormData);
78
- const uniqid__default = /*#__PURE__*/_interopDefaultLegacy(uniqid);
79
73
 
80
74
  var __accessCheck = (obj, member, msg) => {
81
75
  if (!member.has(obj))
@@ -96,6 +90,13 @@ var __privateSet = (obj, member, value, setter) => {
96
90
  return value;
97
91
  };
98
92
  var _client, _isTrackingActive, _anonymousId, _userId, _repository;
93
+ var EventType;
94
+ (function(EventType2) {
95
+ EventType2["DownloadLibrary"] = "SliceMachine Download Library";
96
+ EventType2["InitStart"] = "SliceMachine Init Start";
97
+ EventType2["InitIdentify"] = "SliceMachine Init Identify";
98
+ EventType2["InitDone"] = "SliceMachine Init Done";
99
+ })(EventType || (EventType = {}));
99
100
  class InitTracker {
100
101
  constructor() {
101
102
  __privateAdd(this, _client, null);
@@ -162,16 +163,16 @@ class InitTracker {
162
163
  return this._identifyEvent(userId, intercomHash);
163
164
  }
164
165
  trackDownloadLibrary(library) {
165
- return this._trackEvent("SliceMachine Download Library" /* DownloadLibrary */, { library });
166
+ return this._trackEvent(EventType.DownloadLibrary, { library });
166
167
  }
167
168
  trackInitIdentify() {
168
- return this._trackEvent("SliceMachine Init Identify" /* InitIdentify */);
169
+ return this._trackEvent(EventType.InitIdentify);
169
170
  }
170
171
  trackInitStart(repoDomain) {
171
- return this._trackEvent("SliceMachine Init Start" /* InitStart */, { repo: repoDomain });
172
+ return this._trackEvent(EventType.InitStart, { repo: repoDomain });
172
173
  }
173
174
  trackInitDone(framework) {
174
- return this._trackEvent("SliceMachine Init Done" /* InitDone */, { framework });
175
+ return this._trackEvent(EventType.InitDone, { framework });
175
176
  }
176
177
  }
177
178
  _client = new WeakMap();
@@ -229,7 +230,7 @@ const logs = /*#__PURE__*/Object.freeze({
229
230
  });
230
231
 
231
232
  const { Cookie } = core.Utils;
232
- const { DEFAULT_BASE: DEFAULT_BASE$1, DEFAULT_SERVER_PORT } = core.CONSTS;
233
+ const { DEFAULT_BASE, DEFAULT_SERVER_PORT } = core.CONSTS;
233
234
  const { bold, underline, spinner, writeError } = logs;
234
235
  const isHandlerData = (data) => {
235
236
  if (typeof data != "object")
@@ -272,13 +273,16 @@ const authenticationHandler = (server) => (onSuccess, onFail) => {
272
273
  }
273
274
  };
274
275
  };
276
+ function stripTrailingSlash(str) {
277
+ return str.endsWith("/") ? str.slice(0, -1) : str;
278
+ }
275
279
  function buildServer(base, port, host) {
276
280
  const server = hapi__namespace.server({
277
281
  port,
278
282
  host,
279
283
  routes: {
280
284
  cors: {
281
- origin: [base],
285
+ origin: [stripTrailingSlash(base)],
282
286
  headers: ["Origin", "X-Requested-With", "Content-Type", "Accept"]
283
287
  }
284
288
  }
@@ -301,7 +305,7 @@ function askSingleChar(title) {
301
305
  process.stdin.on("data", handler);
302
306
  });
303
307
  }
304
- async function startServerAndOpenBrowser(url, action, base = DEFAULT_BASE$1, port = DEFAULT_SERVER_PORT) {
308
+ async function startServerAndOpenBrowser(url, action, base = DEFAULT_BASE, port = DEFAULT_SERVER_PORT) {
305
309
  const confirmation = await askSingleChar(`>> Press any key to open the browser to ${action} or q to exit:`);
306
310
  if (confirmation === "q" || confirmation === "")
307
311
  return process.exit(-1);
@@ -338,46 +342,92 @@ async function startServerAndOpenBrowser(url, action, base = DEFAULT_BASE$1, por
338
342
  }
339
343
 
340
344
  async function startAuth({
341
- base,
345
+ client,
342
346
  url,
343
347
  action
344
348
  }) {
345
- const { onLoginFail } = await startServerAndOpenBrowser(url, action, base);
349
+ const { onLoginFail } = await startServerAndOpenBrowser(url, action, client.apisEndpoints.Wroom);
346
350
  try {
347
- await core.Utils.Poll.startPolling(() => Auth.validateSession(base), (user) => !!user, 3e3, 60);
351
+ await core.Utils.Poll.startPolling(() => Auth.validateSession(client), (isSessionValid) => isSessionValid == true, 3e3, 60);
348
352
  return;
349
353
  } catch (e) {
350
354
  onLoginFail();
351
355
  }
352
356
  }
353
357
  const Auth = {
354
- login: async (base) => {
355
- const endpoints = Prismic.Endpoints.buildEndpoints(base);
358
+ login: async (client) => {
359
+ const endpoints = Prismic.Endpoints.buildEndpoints(client.apisEndpoints.Wroom);
356
360
  return startAuth({
357
- base,
361
+ client,
358
362
  url: endpoints.Dashboard.cliLogin,
359
363
  action: "login"
360
364
  });
361
365
  },
362
- signup: async (base) => {
363
- const endpoints = Prismic.Endpoints.buildEndpoints(base);
364
- return startAuth({
365
- base,
366
- url: endpoints.Dashboard.cliSignup,
367
- action: "signup"
368
- });
369
- },
370
- logout: () => Prismic.PrismicSharedConfigManager.remove(),
371
- validateSession: async (requiredBase) => {
372
- const config = Prismic.PrismicSharedConfigManager.get();
373
- if (!config.cookies.length)
374
- return Promise.resolve(null);
375
- if (requiredBase != config.base)
376
- return Promise.resolve(null);
377
- return Prismic.Communication.validateSession(config.cookies, requiredBase).catch(() => null);
366
+ validateSession: async (client) => {
367
+ const authToken = Prismic.PrismicSharedConfigManager.getAuth();
368
+ return client.updateAuthenticationToken(authToken).profile().then((userProfile) => {
369
+ Prismic.PrismicSharedConfigManager.setProperties({
370
+ shortId: userProfile.shortId,
371
+ intercomHash: userProfile.intercomHash
372
+ });
373
+ return true;
374
+ }).catch(() => false);
378
375
  }
379
376
  };
380
377
 
378
+ class InitClient extends client.Client {
379
+ async listRepositories() {
380
+ return client.getAndValidateResponse(this._get(`${this.apisEndpoints.Users}repositories`), "repository list", t__namespace.array(core.Models.Repository));
381
+ }
382
+ async createRepository(domain, framework) {
383
+ const data = {
384
+ domain,
385
+ framework,
386
+ plan: "personal",
387
+ isAnnual: "false",
388
+ role: "developer"
389
+ };
390
+ return this._fetch({
391
+ method: "post",
392
+ url: `${this.apisEndpoints.Wroom}authentication/newrepository?app=slicemachine`,
393
+ data,
394
+ headers: {
395
+ Cookie: Prismic.PrismicSharedConfigManager.get().cookies,
396
+ "User-Agent": "prismic-cli/sm"
397
+ }
398
+ }).then(() => domain);
399
+ }
400
+ async domainExist(domain) {
401
+ return client.getAndValidateResponse(this._get(`${this.apisEndpoints.Wroom}app/dashboard/repositories/${domain}/exists`), "repository exists", t__namespace.boolean);
402
+ }
403
+ async pushDocuments(signature, documents, cookies) {
404
+ if (!this.repository)
405
+ throw new Error("Repository undefined in the client");
406
+ const repositoryDirectUrl = new URL(this.apisEndpoints.Wroom);
407
+ repositoryDirectUrl.hostname = `${this.repository}.${repositoryDirectUrl.hostname}`;
408
+ return this._fetch({
409
+ method: "post",
410
+ url: `${repositoryDirectUrl.toString()}starter/documents`,
411
+ data: { signature, documents: JSON.stringify(documents) },
412
+ headers: {
413
+ Cookie: cookies,
414
+ "User-Agent": "prismic-cli/0"
415
+ }
416
+ });
417
+ }
418
+ }
419
+
420
+ async function lsdir(dir) {
421
+ return fs__default["default"].promises.readdir(dir).then((dirs) => {
422
+ return dirs.filter((name) => fs__default["default"].statSync(path__default["default"].join(dir, name)).isDirectory()).map((subdirectory) => path__default["default"].join(dir, subdirectory));
423
+ });
424
+ }
425
+ async function lsfiles(dir) {
426
+ return fs__default["default"].promises.readdir(dir).then((dirs) => {
427
+ return dirs.filter((name) => fs__default["default"].statSync(path__default["default"].join(dir, name)).isFile()).map((file) => path__default["default"].join(dir, file));
428
+ });
429
+ }
430
+
381
431
  function findArgument(args, name) {
382
432
  const flagIndex = args.indexOf(`--${name}`);
383
433
  if (flagIndex === -1)
@@ -389,7 +439,21 @@ function findArgument(args, name) {
389
439
  return;
390
440
  return flagValue;
391
441
  }
442
+ function findFlag(args, name) {
443
+ const toFind = `--${name}`;
444
+ return args.includes(toFind);
445
+ }
392
446
  const execCommand = util__default["default"].promisify(child_process.exec);
447
+ function getApplicationMode(argumentValue) {
448
+ switch (argumentValue) {
449
+ case client.ApplicationMode.PROD:
450
+ case client.ApplicationMode.STAGE:
451
+ case client.ApplicationMode.DEV:
452
+ return argumentValue;
453
+ default:
454
+ return null;
455
+ }
456
+ }
393
457
 
394
458
  const {
395
459
  PRISMIC_CLIENT,
@@ -459,16 +523,15 @@ function validatePkg(cwd) {
459
523
  }
460
524
  }
461
525
 
462
- function createRepository(domain, framework, cookies, base) {
526
+ function createRepository(client, domain, framework) {
463
527
  const spinner = spinner$1("Creating Prismic Repository");
464
528
  spinner.start();
465
- return Prismic__namespace.Communication.createRepository(domain, cookies, framework, base).then((res) => {
466
- const addressUrl = new URL(base);
467
- const repoDomainName = res.data.domain || domain;
468
- addressUrl.hostname = `${repoDomainName}.${addressUrl.hostname}`;
529
+ return client.createRepository(domain, framework).then((domain2) => {
530
+ const addressUrl = new URL(client.apisEndpoints.Wroom);
531
+ addressUrl.hostname = `${domain2}.${addressUrl.hostname}`;
469
532
  const address = addressUrl.toString();
470
533
  spinner.succeed(`We created your new repository ${address}`);
471
- return repoDomainName;
534
+ return domain2;
472
535
  }).catch((error) => {
473
536
  spinner.fail(`Error creating repository ${domain}`);
474
537
  if (error.message) {
@@ -480,14 +543,38 @@ function createRepository(domain, framework, cookies, base) {
480
543
  });
481
544
  }
482
545
 
546
+ async function validateRepositoryName(client, name) {
547
+ const domain = name.trim();
548
+ const errors = [];
549
+ const startsWithLetter = /^[a-zA-Z]/.test(domain);
550
+ if (!startsWithLetter)
551
+ errors.push("Must start with a letter.");
552
+ const acceptedChars = /^[a-z0-9-]+$/.test(domain);
553
+ if (!acceptedChars)
554
+ errors.push("Must contain only lowercase letters, numbers and hyphens.");
555
+ const fourCharactersOrMore = domain.length >= 4;
556
+ if (!fourCharactersOrMore)
557
+ errors.push("Must have four or more alphanumeric characters and/or hyphens.");
558
+ const endsWithALetterOrNumber = /[a-z0-9]$/.test(domain);
559
+ if (!endsWithALetterOrNumber)
560
+ errors.push("Must end in a letter or a number.");
561
+ const thirtyCharacterOrLess = domain.length <= 30;
562
+ if (!thirtyCharacterOrLess)
563
+ errors.push("Must be 30 characters or less");
564
+ if (errors.length > 0) {
565
+ const errorString = errors.map((d, i) => `(${i + 1}: ${d}`).join(" ");
566
+ const msg = `Validation errors: ${errorString}`;
567
+ return Promise.reject(new Error(msg));
568
+ }
569
+ return client.domainExist(domain).then((isAvailable) => isAvailable ? true : Promise.reject(new Error(`${name} is already in use`))).catch(() => Promise.reject(new Error(`${name} is already in use`)));
570
+ }
571
+
483
572
  const CREATE_REPO = "$_CREATE_REPO";
484
- const DEFAULT_BASE = core.CONSTS.DEFAULT_BASE;
485
- function prettyRepoName(address, value) {
486
- const repoName = value ? cyan(value) : dim.cyan("repo-name");
487
- return `${cyan.dim(`${address.protocol}//`)}${repoName}${cyan.dim(`.${address.hostname}`)}`;
573
+ function prettyRepoName(address, domain) {
574
+ return `${cyan.dim(`${address.protocol}//`)}${cyan(domain)}${cyan.dim(`.${address.hostname}`)}`;
488
575
  }
489
- async function promptForRepoDomain(base, defaultValue) {
490
- const address = new URL(base);
576
+ async function promptForRepoDomain(client, defaultValue) {
577
+ const address = new URL(client.apisEndpoints.Wroom);
491
578
  writeInfo("The name acts as a domain/endpoint for your content repo and should be completely unique.");
492
579
  return inquirer__namespace.prompt([
493
580
  {
@@ -496,11 +583,8 @@ async function promptForRepoDomain(base, defaultValue) {
496
583
  type: "input",
497
584
  required: true,
498
585
  default: defaultValue,
499
- transformer: (value) => prettyRepoName(address, value || defaultValue),
500
- async validate(name) {
501
- const result = await Prismic__namespace.Communication.validateRepositoryName(name, base, false);
502
- return result === name || result;
503
- }
586
+ transformer: (value) => prettyRepoName(address, value || defaultValue || "repository"),
587
+ validate: (name) => validateRepositoryName(client, name)
504
588
  }
505
589
  ]).then((res) => res.repoDomain);
506
590
  }
@@ -554,26 +638,26 @@ function sortReposForPrompt(repos, base, cwd) {
554
638
  createNew
555
639
  ]).sort(orderPrompts(maybeConfiguredRepoName));
556
640
  }
557
- async function chooseOrCreateARepository(cwd, framework, cookies, base = DEFAULT_BASE, domain) {
558
- const token = core.Utils.Cookie.parsePrismicAuthToken(cookies);
559
- const repos = await Prismic__namespace.Communication.listRepositories(token, base);
560
- const hasRepo = domain && repos.find((d) => d.domain === domain);
561
- if (hasRepo)
562
- return domain;
563
- if (repos.length === 0) {
564
- const domainName = await promptForRepoDomain(base, domain);
565
- return await createRepository(domainName, framework, cookies, base);
641
+ async function chooseOrCreateARepository(client, cwd, framework, preSelectedRepository) {
642
+ const repositories = await client.listRepositories();
643
+ const isPreSelectedValid = preSelectedRepository && repositories.find((repository) => repository.domain === preSelectedRepository);
644
+ if (isPreSelectedValid)
645
+ return preSelectedRepository;
646
+ if (repositories.length === 0) {
647
+ const domainName = await promptForRepoDomain(client, preSelectedRepository);
648
+ await createRepository(client, domainName, framework);
649
+ return domainName;
566
650
  }
567
- const choices = sortReposForPrompt(repos, base, cwd);
651
+ const choices = sortReposForPrompt(repositories, client.apisEndpoints.Wroom, cwd);
568
652
  const numberOfDisabledRepos = choices.filter((repo) => {
569
653
  if (repo instanceof Separator__default["default"])
570
654
  return false;
571
655
  return repo.disabled;
572
656
  }).length;
573
- const res = await inquirer__namespace.prompt([
657
+ const promptResult = await inquirer__namespace.prompt([
574
658
  {
575
659
  type: "list",
576
- name: "chosenRepo",
660
+ name: "chosenRepository",
577
661
  default: 0,
578
662
  required: true,
579
663
  message: "Connect a Prismic Repository or create a new one",
@@ -581,11 +665,12 @@ async function chooseOrCreateARepository(cwd, framework, cookies, base = DEFAULT
581
665
  pageSize: numberOfDisabledRepos + 2 <= 7 ? 7 : numberOfDisabledRepos + 2
582
666
  }
583
667
  ]);
584
- if (res.chosenRepo === CREATE_REPO) {
585
- const domainName = await promptForRepoDomain(base, domain);
586
- return await createRepository(domainName, framework, cookies, base);
668
+ if (promptResult.chosenRepository === CREATE_REPO) {
669
+ const domainName = await promptForRepoDomain(client, preSelectedRepository);
670
+ await createRepository(client, domainName, framework);
671
+ return domainName;
587
672
  }
588
- return res.chosenRepo;
673
+ return promptResult.chosenRepository;
589
674
  }
590
675
 
591
676
  async function promptForFramework() {
@@ -646,56 +731,21 @@ async function detectFramework(cwd) {
646
731
  }
647
732
  }
648
733
 
649
- async function getUserProfile(cookies, base = core.CONSTS.DEFAULT_BASE) {
650
- const userServiceBase = core.CONSTS.DEFAULT_BASE === base ? core.CONSTS.USER_SERVICE_BASE : core.CONSTS.USER_SERVICE_STAGING_BASE;
651
- const url = new URL(userServiceBase);
652
- url.pathname = "profile";
653
- const endpoint = url.toString();
654
- const token = core.Utils.Cookie.parsePrismicAuthToken(cookies);
655
- return axios__default["default"].get(endpoint, {
656
- headers: {
657
- Authorization: `Bearer ${token}`
658
- }
659
- }).then((res) => _function.pipe(core.Models.UserProfile.decode(res.data), Either.fold(() => {
660
- throw new Error("Can't parse user profile");
661
- }, (data) => data)));
662
- }
663
- async function validateSessionAndGetProfile(base = core.CONSTS.DEFAULT_BASE) {
664
- const config = Prismic__namespace.PrismicSharedConfigManager.get();
665
- if (!config.cookies.length)
666
- return Promise.resolve(null);
667
- if (base != config.base)
668
- return Promise.resolve(null);
669
- try {
670
- const info = await Prismic__namespace.Communication.validateSession(config.cookies, base);
671
- const profile = await getUserProfile(config.cookies, base).catch(() => null);
672
- if (profile == null ? void 0 : profile.shortId) {
673
- Prismic__namespace.PrismicSharedConfigManager.setProperties({
674
- shortId: profile.shortId,
675
- intercomHash: profile.intercomHash
676
- });
677
- }
678
- return { info, profile };
679
- } catch (e) {
680
- return null;
681
- }
682
- }
683
-
684
- async function loginOrBypass(base) {
685
- const user = await validateSessionAndGetProfile(base).catch((err) => console.log(err));
734
+ async function loginOrBypass(client) {
735
+ const user = await client.profile().catch(() => null);
686
736
  if (user) {
687
- const email = user.info.email;
737
+ const email = user.email;
688
738
  writeCheck(`Logged in as ${bold$1(email)}`);
689
739
  return user;
690
- } else {
691
- await Auth.login(base);
692
- const user2 = await validateSessionAndGetProfile(base);
693
- return user2;
694
740
  }
741
+ await Auth.login(client);
742
+ client.updateAuthenticationToken(Prismic.PrismicSharedConfigManager.getAuth());
743
+ const userAfterLogin = await client.profile();
744
+ return userAfterLogin;
695
745
  }
696
746
 
697
747
  const defaultSliceMachineVersion = "0.0.41";
698
- async function configureProject(cwd, base, repositoryDomainName, framework, sliceLibPath = [], tracking = true) {
748
+ async function configureProject(client, cwd, repositoryDomainName, framework, sliceLibPath = [], tracking = true) {
699
749
  const frameworkName = NodeUtils__namespace.Framework.fancyName(framework.value);
700
750
  const spinner = spinner$1(`Configuring your ${frameworkName} and Prismic project...`);
701
751
  spinner.start();
@@ -707,7 +757,7 @@ async function configureProject(cwd, base, repositoryDomainName, framework, slic
707
757
  const libs = manifest.content && manifest.content.libraries && manifest.content.libraries.length > 0 ? manifest.content.libraries : ["@/slices"];
708
758
  const manifestUpdated = {
709
759
  ...manifestAlreadyExistWithContent ? manifest.content : { _latest: sliceMachineVersionInstalled },
710
- apiEndpoint: Prismic__namespace.Endpoints.buildRepositoryEndpoint(base, repositoryDomainName),
760
+ apiEndpoint: Prismic__namespace.Endpoints.buildRepositoryEndpoint(client.apisEndpoints.Wroom, repositoryDomainName),
711
761
  libraries: [...libs, ...sliceLibPath],
712
762
  ...framework.manuallyAdded ? { framework: framework.value } : {},
713
763
  ...!tracking ? { tracking } : {}
@@ -752,11 +802,19 @@ const extractVersionNumberFromSemver = (semver) => {
752
802
  return null;
753
803
  };
754
804
 
755
- function displayFinalMessage(cwd) {
805
+ function displayFinalMessage(cwd, wasStarter, reponame, base) {
756
806
  const yarnLock = NodeUtils__namespace.Files.exists(NodeUtils__namespace.YarnLockPath(cwd));
757
807
  const command = `${yarnLock ? "yarn" : "npm"} run ${core.CONSTS.SCRIPT_NAME}`;
758
808
  console.log();
759
- console.log(`${white("\u25A0")} Run ${purple(command)} to start Slice Machine`);
809
+ if (wasStarter) {
810
+ const repoUrl = new URL(base);
811
+ repoUrl.hostname = `${reponame}.${repoUrl.hostname}`;
812
+ const urlAsString = repoUrl.toString();
813
+ const message = `${white("\u25A0")} Start editing your content in Prismic ${purple(urlAsString)}`;
814
+ console.log(message);
815
+ } else {
816
+ console.log(`${white("\u25A0")} Run ${purple(command)} to launch Slice Machine and create your first Custom Type`);
817
+ }
760
818
  }
761
819
 
762
820
  const Dependencies = {
@@ -864,100 +922,6 @@ async function installLib(cwd, libGithubPath, branch = "HEAD") {
864
922
  }
865
923
  }
866
924
 
867
- function handelErrors(prefix, err) {
868
- if (axios__default["default"].isAxiosError(err) && err.response) {
869
- writeError$1(`${prefix} | [${err.response.status}]: ${err.response.statusText}`);
870
- } else if (err instanceof Error) {
871
- writeError$1(`${prefix} ${err.message}`);
872
- } else {
873
- writeError$1(`${prefix} ${String(err)}`);
874
- }
875
- }
876
- async function getRemoteSliceIds(customTypeApiEndpoint, repository, authorization) {
877
- const addr = `${stripLastSlash(customTypeApiEndpoint)}/slices`;
878
- return axios__default["default"].get(addr, {
879
- headers: {
880
- Authorization: `Bearer ${authorization}`,
881
- repository
882
- }
883
- }).then((res) => {
884
- return Array.isArray(res.data) ? res.data.map((model) => model.id) : [];
885
- });
886
- }
887
- async function sendModelToPrismic(repository, authorization, customTypesApiEndpoint, remoteSliceIds, model) {
888
- const data = models.Slices.fromSM(model);
889
- const updateOrInsertUrl = `${customTypesApiEndpoint}slices/${remoteSliceIds.includes(model.id) ? "update" : "insert"}`;
890
- return axios__default["default"].post(updateOrInsertUrl, data, {
891
- headers: {
892
- Authorization: `Bearer ${authorization}`,
893
- repository
894
- }
895
- }).then(() => {
896
- return;
897
- }).catch((err) => {
898
- handelErrors(`sending slice ${model.id}, please try again. If the problem persists, contact us.`, err);
899
- throw err;
900
- });
901
- }
902
- async function sendManyModelsToPrismic(repository, authorization, customTypesApiEndpoint, remoteSliceIds, models) {
903
- return Promise.all(models.map((model) => sendModelToPrismic(repository, authorization, customTypesApiEndpoint, remoteSliceIds, model))).then(() => {
904
- return;
905
- }).catch(() => {
906
- process.exit(1);
907
- });
908
- }
909
- function stripLastSlash(str) {
910
- return str.replace(/\/*$/g, "");
911
- }
912
- function getRemoteCustomTypeIds(customTypeApiEndpoint, repository, authorization) {
913
- const addr = `${stripLastSlash(customTypeApiEndpoint)}/customtypes`;
914
- return axios__default["default"].get(addr, {
915
- headers: {
916
- Authorization: `Bearer ${authorization}`,
917
- repository
918
- }
919
- }).then((res) => {
920
- return Array.isArray(res.data) ? res.data.map((ct) => ct.id) : [];
921
- });
922
- }
923
- async function sendCustomTypeToPrismic(repository, authorization, customTypeApiEndpoint, remoteCustomTypeIds, customType) {
924
- const shouldUpdate = remoteCustomTypeIds.includes(customType.id);
925
- const addr = `${stripLastSlash(customTypeApiEndpoint)}/customtypes/${shouldUpdate ? "update" : "insert"}`;
926
- return axios__default["default"].post(addr, customType, {
927
- headers: {
928
- repository,
929
- Authorization: `Bearer ${authorization}`
930
- }
931
- }).then(() => {
932
- return;
933
- }).catch((err) => {
934
- handelErrors(`sending custom type ${customType.id}, please try again. If the problem persists, contact us.`, err);
935
- throw err;
936
- });
937
- }
938
- async function sendManyCustomTypesToPrismic(repository, authorization, customTypeApiEndpoint, remoteCustomTypeIds, customTypes) {
939
- return Promise.all(customTypes.map((customType) => sendCustomTypeToPrismic(repository, authorization, customTypeApiEndpoint, remoteCustomTypeIds, customType))).then(() => {
940
- return;
941
- }).catch(() => {
942
- process.exit(1);
943
- });
944
- }
945
-
946
- const ProductionApisEndpoints = {
947
- Models: "https://customtypes.prismic.io/",
948
- AclProvider: "https://0yyeb2g040.execute-api.us-east-1.amazonaws.com/prod/"
949
- };
950
- const StageApisEndpoints = {
951
- Models: "https://customtypes.wroom.io/",
952
- AclProvider: "https://2iamcvnxf4.execute-api.us-east-1.amazonaws.com/stage/"
953
- };
954
- const getEndpointsFromBase = (base) => {
955
- const url = new URL(base);
956
- if (url.hostname === "wroom.io")
957
- return StageApisEndpoints;
958
- return ProductionApisEndpoints;
959
- };
960
-
961
925
  async function promptToPushSlices() {
962
926
  return inquirer__default["default"].prompt([
963
927
  {
@@ -979,122 +943,75 @@ async function promptToPushCustomTypes() {
979
943
  ]).then((res) => res.pushCustomTypes);
980
944
  }
981
945
 
982
- async function createAcl(address, repository, authorization) {
983
- return axios__default["default"].get(address + "create", {
984
- headers: {
985
- repository,
986
- Authorization: `Bearer ${authorization}`,
987
- "User-Agent": "slice-machine"
988
- }
989
- }).then((res) => res.data);
990
- }
991
- async function createFormForS3(key, filename, filePath, acl) {
992
- const form = new FormData__default["default"]();
993
- Object.entries(acl.values.fields).forEach(([k, value]) => {
994
- form.append(k, value);
995
- });
996
- form.append("key", key);
997
- const contentType = mime__default["default"].getType(filePath);
998
- contentType && form.append("Content-Type", contentType);
999
- return fs__default["default"].promises.readFile(filePath).then((file) => {
1000
- form.append("file", file, { filename });
1001
- return form;
1002
- }).catch(() => {
1003
- writeError$1(`Error reading preview image: ${filename}`);
1004
- return null;
1005
- });
1006
- }
1007
- function createS3Key(repository, sliceName, variationId, filename) {
1008
- return `${repository}/shared-slices/${snakeCase__default["default"](sliceName)}/${snakeCase__default["default"](variationId)}-${uniqid__default["default"]()}/${filename}`;
1009
- }
1010
- async function sendVariationPreviewToS3(acl, repository, sliceName, variationId, filePath) {
1011
- const filename = path__default["default"].basename(filePath);
1012
- const key = createS3Key(repository, sliceName, variationId, filename);
1013
- const form = await createFormForS3(key, filename, filePath, acl);
1014
- if (form === null)
1015
- return null;
1016
- if (form.hasKnownLength() === false) {
1017
- writeError$1(`[slice/push] An error occurred while uploading preview image ${filePath} as length in unknown`);
1018
- }
1019
- const errorMessage = `[slice/push] An error occurred while uploading preview images for ${sliceName}-${variationId} - please contact support`;
1020
- return axios__default["default"].post(acl.values.url, form, {
1021
- headers: {
1022
- ...form.getHeaders(),
1023
- "Content-Length": String(form.getLengthSync())
1024
- }
1025
- }).then((res) => {
1026
- if (res.status !== 204) {
1027
- writeError$1(errorMessage);
1028
- writeError$1(`${res.status}: ${res.statusText}`);
1029
- return null;
1030
- } else {
1031
- return `${acl.imgixEndpoint}/${key}`;
1032
- }
1033
- }).catch((err) => {
1034
- writeError$1(errorMessage);
1035
- if (axios__default["default"].isAxiosError(err) && err.response) {
1036
- writeError$1(`${err.response.status}: ${err.response.statusText}`);
1037
- } else if (err instanceof Error) {
1038
- writeError$1(err.message);
1039
- } else {
1040
- writeError$1(String(err));
1041
- }
1042
- return null;
1043
- });
1044
- }
1045
- async function maybeAddImageUrlToVariation(acl, repository, modelId, pathToScreenShot, variation) {
1046
- const imageUrl = await sendVariationPreviewToS3(acl, repository, modelId, variation.id, pathToScreenShot);
1047
- if (!imageUrl)
946
+ async function updateVariationWithScreenshot(client, acl, screenshotPaths, sliceName, variation) {
947
+ const screenshot = screenshotPaths[variation.id];
948
+ if (!screenshot || !screenshot.path)
949
+ return Promise.resolve(variation);
950
+ return client.uploadScreenshot({
951
+ acl,
952
+ sliceName,
953
+ variationId: variation.id,
954
+ filePath: screenshot.path
955
+ }).then((screenshotUrl) => {
956
+ return {
957
+ ...variation,
958
+ imageUrl: screenshotUrl
959
+ };
960
+ }).catch((error) => {
961
+ writeError$1(`Couldn't upload screenshot slice: ${sliceName} - variation: ${variation.id}`);
962
+ writeError$1(error.message, "Full error:");
1048
963
  return variation;
1049
- return {
1050
- ...variation,
1051
- imageUrl
1052
- };
964
+ });
1053
965
  }
1054
- async function addImageUrlsToVariations(acl, repository, modelId, screenshotPaths, variations) {
1055
- return Promise.all(variations.map(async (variation) => {
1056
- const screenshot = screenshotPaths[variation.id];
1057
- if (!screenshot || !screenshot.path)
1058
- return variation;
1059
- return maybeAddImageUrlToVariation(acl, repository, modelId, screenshot.path, variation);
966
+ async function updateSlicesWithScreenshots(client, acl, components) {
967
+ return Promise.all(components.map(async (component) => {
968
+ const { screenshotPaths, model } = component;
969
+ const variationsUpdated = await Promise.all(model.variations.map(async (variation) => updateVariationWithScreenshot(client, acl, screenshotPaths, model.id, variation)));
970
+ return {
971
+ ...model,
972
+ variations: variationsUpdated
973
+ };
1060
974
  }));
1061
975
  }
1062
- async function maybeUpdateModelVariationsWithImageUrl(acl, repository, component) {
1063
- const { screenshotPaths, model } = component;
1064
- const variations = await addImageUrlsToVariations(acl, repository, model.id, screenshotPaths, model.variations);
1065
- return {
1066
- ...model,
1067
- variations
1068
- };
1069
- }
1070
- async function addImageUrlsToModelVariations(acl, repository, components) {
1071
- return Promise.all(components.map(async (component) => maybeUpdateModelVariationsWithImageUrl(acl, repository, component)));
1072
- }
1073
976
 
1074
- async function sendSlicesFromStarter(base, repository, authorization, libraryPaths, cwd) {
1075
- const endpoints = getEndpointsFromBase(base);
1076
- const libraries = Libraries__namespace.libraries(cwd, libraryPaths);
1077
- if (libraries.length === 0)
977
+ async function sendSlices(client, cwd, manifest) {
978
+ if (!manifest.libraries)
979
+ return Promise.resolve(false);
980
+ const libraries = Libraries__namespace.libraries(cwd, manifest.libraries);
981
+ const components = libraries.reduce((acc, lib) => {
982
+ return [...acc, ...lib.components];
983
+ }, []);
984
+ if (components.length === 0)
1078
985
  return Promise.resolve(false);
1079
- const remoteSlices = await getRemoteSliceIds(endpoints.Models, repository, authorization);
1080
- if (remoteSlices.length) {
986
+ const remoteSlicesIds = await client.getSlices().then((slices) => slices.map((slice) => slice.id));
987
+ if (remoteSlicesIds.length) {
1081
988
  const pushAnyway = await promptToPushSlices();
1082
989
  if (pushAnyway === false)
1083
990
  return Promise.resolve(true);
1084
991
  }
1085
992
  const spinner = spinner$1("Pushing existing Slice models to your repository");
1086
993
  spinner.start();
1087
- const acl = await createAcl(endpoints.AclProvider, repository, authorization);
1088
- const components = libraries.reduce((acc, lib) => {
1089
- return [...acc, ...lib.components];
1090
- }, []);
1091
- const models = await addImageUrlsToModelVariations(acl, repository, components);
1092
- await sendManyModelsToPrismic(repository, authorization, endpoints.Models, remoteSlices, models);
994
+ const acl = await client.createAcl().catch((error) => {
995
+ writeError$1("Uploading screenshots for your slices failed, please contact us.");
996
+ writeError$1(error.message, "Full error:");
997
+ return null;
998
+ });
999
+ const models$1 = acl ? await updateSlicesWithScreenshots(client, acl, components) : components.map((component) => component.model);
1000
+ await Promise.all(models$1.map(async (model) => {
1001
+ const slice = models.Slices.fromSM(model);
1002
+ const promise = remoteSlicesIds.includes(slice.id) ? client.updateSlice(slice) : client.insertSlice(slice);
1003
+ return promise.catch((error) => {
1004
+ writeError$1(`Sending slice ${model.id} - ${error.message}`);
1005
+ throw error;
1006
+ });
1007
+ })).catch(() => {
1008
+ process.exit(1);
1009
+ });
1093
1010
  spinner.succeed();
1094
1011
  return Promise.resolve(true);
1095
1012
  }
1096
1013
 
1097
- function readCustomTypes(cwd) {
1014
+ function readLocalCustomTypes(cwd) {
1098
1015
  const customTypePaths = NodeUtils.CustomTypesPaths(cwd);
1099
1016
  const dir = customTypePaths.value();
1100
1017
  if (NodeUtils.Files.isDirectory(dir) === false)
@@ -1118,12 +1035,11 @@ function readCustomTypes(cwd) {
1118
1035
  }, []);
1119
1036
  return files;
1120
1037
  }
1121
- async function sendCustomTypesFromStarter(repository, authorization, base, cwd) {
1122
- const customTypeApiEndpoint = getEndpointsFromBase(base).Models;
1123
- const customTypes = readCustomTypes(cwd);
1124
- if (customTypes.length === 0)
1038
+ async function sendCustomTypes(client, cwd) {
1039
+ const localCustomTypes = readLocalCustomTypes(cwd);
1040
+ if (localCustomTypes.length === 0)
1125
1041
  return Promise.resolve(false);
1126
- const remoteCustomTypeIds = await getRemoteCustomTypeIds(customTypeApiEndpoint, repository, authorization);
1042
+ const remoteCustomTypeIds = await client.getCustomTypes().then((customTypes) => customTypes.map((customType) => customType.id));
1127
1043
  if (remoteCustomTypeIds.length) {
1128
1044
  const shouldPush = await promptToPushCustomTypes();
1129
1045
  if (shouldPush === false)
@@ -1131,50 +1047,112 @@ async function sendCustomTypesFromStarter(repository, authorization, base, cwd)
1131
1047
  }
1132
1048
  const spinner = spinner$1("Pushing existing custom types to your repository");
1133
1049
  spinner.start();
1134
- await sendManyCustomTypesToPrismic(repository, authorization, customTypeApiEndpoint, remoteCustomTypeIds, customTypes);
1050
+ await Promise.all(localCustomTypes.map(async (customType) => {
1051
+ const promise = remoteCustomTypeIds.includes(customType.id) ? client.updateCustomType(customType) : client.insertCustomType(customType);
1052
+ return promise.catch((error) => {
1053
+ writeError$1(`Sending custom type ${customType.id} - ${error.message}`);
1054
+ throw error;
1055
+ });
1056
+ })).catch(() => {
1057
+ process.exit(1);
1058
+ });
1135
1059
  spinner.succeed();
1136
1060
  return Promise.resolve(true);
1137
1061
  }
1138
1062
 
1139
- async function sendStarterData(repository, base, cookies, cwd) {
1140
- const smJson = NodeUtils.retrieveManifest(cwd);
1141
- const hasDocuments = NodeUtils.Files.exists(path__default["default"].join(cwd, "documents"));
1142
- if (smJson.exists === false || hasDocuments === false)
1063
+ const SignatureFileReader = t__namespace.type({
1064
+ signature: t__namespace.string
1065
+ });
1066
+ async function readSignatureFile(cwd) {
1067
+ const pathToFile = path__default["default"].join(cwd, "documents", "index.json");
1068
+ return fs__default["default"].promises.readFile(pathToFile, "utf-8").then((res) => {
1069
+ const data = JSON.parse(res);
1070
+ return Either.getOrElseW(() => {
1071
+ throw new Error("Unable to read document signature file");
1072
+ })(SignatureFileReader.decode(data));
1073
+ });
1074
+ }
1075
+ async function readDocuments(cwd) {
1076
+ const documentDir = path__default["default"].join(cwd, "documents");
1077
+ const dirs = await lsdir(documentDir);
1078
+ const files = (await Promise.all(dirs.map((dir) => lsfiles(dir)))).flat();
1079
+ const documentObj = files.reduce((acc, file) => {
1080
+ const filename = path__default["default"].parse(file).name;
1081
+ const fileContent = fs__default["default"].readFileSync(file, "utf-8");
1082
+ const json = JSON.parse(fileContent);
1083
+ return { ...acc, [filename]: json };
1084
+ }, {});
1085
+ return documentObj;
1086
+ }
1087
+ async function sendDocuments(client, cwd) {
1088
+ const pathToDocuments = path__default["default"].join(cwd, "documents");
1089
+ const pathToSignatureFile = path__default["default"].join(pathToDocuments, "index.json");
1090
+ if (!fs__default["default"].existsSync(pathToSignatureFile))
1091
+ return Promise.resolve(false);
1092
+ const signatureObj = await readSignatureFile(cwd);
1093
+ const documents = await readDocuments(cwd);
1094
+ if (Object.keys(documents).length === 0)
1095
+ return Promise.resolve(false);
1096
+ const spinner = spinner$1("Pushing existing documents to your repository");
1097
+ spinner.start();
1098
+ return client.pushDocuments(signatureObj.signature, documents, SharedConfig.PrismicSharedConfigManager.get().cookies).then(() => {
1099
+ spinner.succeed();
1100
+ fs__default["default"].rmSync(pathToDocuments, { recursive: true, force: true });
1101
+ return true;
1102
+ }).catch((e) => {
1103
+ var _a;
1104
+ spinner.fail();
1105
+ if (((_a = e.response) == null ? void 0 : _a.data) === "Repository should not contain documents") {
1106
+ writeError$1("The selected repository is not empty, documents cannot be uploaded. Please choose an empty repository or delete the documents contained in your repository.");
1107
+ } else {
1108
+ writeError$1("Sending documents failed, please try again. If the problem persists, contact us.");
1109
+ writeError$1(`Full error: ${e.code || 500} - ${e.message}`);
1110
+ }
1111
+ process.exit(1);
1112
+ });
1113
+ }
1114
+
1115
+ async function sendStarterData(client, cwd, pushDocuments = true) {
1116
+ const manifest = NodeUtils.retrieveManifest(cwd);
1117
+ const documentsPath = path__default["default"].join(cwd, "documents");
1118
+ const hasDocuments = NodeUtils.Files.exists(documentsPath);
1119
+ if (manifest.exists === false || hasDocuments === false)
1143
1120
  return Promise.resolve(false);
1144
- const authTokenFromCookie = cookie.parsePrismicAuthToken(cookies);
1145
- if (smJson.content && smJson.content.libraries) {
1146
- await sendSlicesFromStarter(base, repository, authTokenFromCookie, smJson.content.libraries, cwd);
1121
+ if (manifest.content)
1122
+ await sendSlices(client, cwd, manifest.content);
1123
+ await sendCustomTypes(client, cwd);
1124
+ if (!pushDocuments) {
1125
+ fs__default["default"].rmSync(documentsPath, { recursive: true, force: true });
1126
+ return Promise.resolve(true);
1147
1127
  }
1148
- return sendCustomTypesFromStarter(repository, authTokenFromCookie, base, cwd);
1128
+ return sendDocuments(client, cwd);
1149
1129
  }
1150
1130
 
1151
1131
  async function init() {
1152
1132
  const cwd = findArgument(process.argv, "cwd") || process.cwd();
1153
- const base = findArgument(process.argv, "base") || core.CONSTS.DEFAULT_BASE;
1133
+ const mode = getApplicationMode(findArgument(process.argv, "mode")) || client.ApplicationMode.PROD;
1154
1134
  const lib = findArgument(process.argv, "library");
1155
1135
  const branch = findArgument(process.argv, "branch");
1156
1136
  const isTrackingAvailable = findArgument(process.argv, "tracking") !== "false";
1157
- const maybeRepositorySubdomain = findArgument(process.argv, "repository");
1137
+ const preSelectedRepository = findArgument(process.argv, "repository");
1138
+ const pushDocuments = !findFlag(process.argv, "no-docs");
1158
1139
  Tracker.get().initialize("JfTfmHaATChc4xueS7RcCBsixI71dJIJ" , isTrackingAvailable);
1159
- void Tracker.get().trackInitStart(maybeRepositorySubdomain);
1140
+ void Tracker.get().trackInitStart(preSelectedRepository);
1141
+ const client$1 = new InitClient(mode, null, Prismic__default["default"].PrismicSharedConfigManager.getAuth());
1160
1142
  console.log(purple("You're about to configure Slicemachine... Press ctrl + C to cancel"));
1161
1143
  validatePkg(cwd);
1162
- const user = await loginOrBypass(base);
1163
- if (!user)
1164
- throw new Error("The user should be logged in!");
1165
- if (user.profile) {
1166
- Tracker.get().identifyUser(user.profile.shortId, user.profile.intercomHash);
1167
- }
1144
+ const user = await loginOrBypass(client$1);
1145
+ Tracker.get().identifyUser(user.shortId, user.intercomHash);
1168
1146
  void Tracker.get().trackInitIdentify();
1169
- const config = Prismic__default["default"].PrismicSharedConfigManager.get();
1170
1147
  const frameworkResult = await detectFramework(cwd);
1171
- const repositoryDomainName = await chooseOrCreateARepository(cwd, frameworkResult.value, config.cookies, config.base, maybeRepositorySubdomain);
1172
- Tracker.get().setRepository(repositoryDomainName);
1148
+ const repository = await chooseOrCreateARepository(client$1, cwd, frameworkResult.value, preSelectedRepository);
1149
+ Tracker.get().setRepository(repository);
1150
+ client$1.updateRepository(repository);
1173
1151
  const sliceLibPath = lib ? await installLib(cwd, lib, branch) : void 0;
1174
- const wasStarter = await sendStarterData(repositoryDomainName, config.base, config.cookies, cwd);
1175
- await configureProject(cwd, base, repositoryDomainName, frameworkResult, sliceLibPath, isTrackingAvailable);
1152
+ const wasStarter = await sendStarterData(client$1, cwd, pushDocuments);
1153
+ await configureProject(client$1, cwd, repository, frameworkResult, sliceLibPath, isTrackingAvailable);
1176
1154
  await installRequiredDependencies(cwd, frameworkResult.value, wasStarter);
1177
- displayFinalMessage(cwd);
1155
+ displayFinalMessage(cwd, wasStarter, repository, client$1.apisEndpoints.Wroom);
1178
1156
  }
1179
1157
  init().then(() => {
1180
1158
  process.exit(0);