@remkoj/optimizely-graph-cli 1.0.3 → 2.0.0-pre1

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.
Files changed (2) hide show
  1. package/bin/index.js +180 -82
  2. package/package.json +8 -7
package/bin/index.js CHANGED
@@ -18,7 +18,7 @@ import createAdminApi, { isApiError } from '@remkoj/optimizely-graph-client/admi
18
18
  import chalk from 'chalk';
19
19
  import figures from 'figures';
20
20
  import Table from 'cli-table3';
21
- import { createHmacFetch } from '@remkoj/optimizely-graph-client/client';
21
+ import ChannelRepository from '@remkoj/optimizely-graph-client/channels';
22
22
  import fs from 'node:fs';
23
23
 
24
24
  function processEnvFile(suffix = "") {
@@ -58,7 +58,7 @@ function createCliApp(scriptName, version, epilogue) {
58
58
  .option('verbose', { description: "Enable query logging", boolean: true, type: 'boolean', demandOption: false, default: config.query_log })
59
59
  .demandCommand(1, 1)
60
60
  .showHelpOnFail(true)
61
- .epilogue(epilogue ?? `Copyright Remko Jantzen - 2023-${(new Date(Date.now())).getFullYear()}`)
61
+ .epilogue(`Copyright Remko Jantzen - 2023-${(new Date(Date.now())).getFullYear()}`)
62
62
  .help();
63
63
  }
64
64
  function getArgsConfig(args) {
@@ -83,7 +83,7 @@ function getFrontendURL(config) {
83
83
  }
84
84
 
85
85
  const publishToVercelModule$2 = {
86
- command: ['register [path] [verb]'],
86
+ command: ['webhook:create [path] [verb]', 'wc [path] [verb]', 'register [path] [verb]'],
87
87
  handler: async (args) => {
88
88
  const cgConfig = getArgsConfig(args);
89
89
  const frontendUrl = getFrontendURL(cgConfig);
@@ -164,7 +164,7 @@ const publishToVercelModule$2 = {
164
164
  };
165
165
 
166
166
  const publishToVercelModule$1 = {
167
- command: ['unregister [path]'],
167
+ command: ['webhook:delete [path]', 'wd [path]', 'unregister [path]'],
168
168
  handler: async (args) => {
169
169
  const cgConfig = getArgsConfig(args);
170
170
  const hookPath = args.path ?? '/';
@@ -245,7 +245,7 @@ const publishToVercelModule$1 = {
245
245
  };
246
246
 
247
247
  const publishToVercelModule = {
248
- command: ['list'],
248
+ command: ['webhook:list', 'wl', 'list'],
249
249
  handler: async (args) => {
250
250
  const cgConfig = getArgsConfig(args);
251
251
  if (!cgConfig.app_key || !cgConfig.secret)
@@ -284,74 +284,59 @@ const publishToVercelModule = {
284
284
 
285
285
  const DEFAULT_CONFIG_FILE = "src/site-config.ts";
286
286
  const createSiteConfigModule = {
287
- command: ['site-config [file_path]'],
287
+ command: ['config:create [file_path]', 'cc [file_path]', 'site-config [file_path]'],
288
288
  handler: async (args) => {
289
289
  const cgConfig = getArgsConfig(args);
290
290
  if (!cgConfig.app_key || !cgConfig.secret)
291
291
  throw new Error("Make sure both the Optimizely Graph App Key & Secret have been defined");
292
- const cgFetch = createHmacFetch(cgConfig.app_key, cgConfig.secret);
293
292
  const siteHost = getFrontendURL(cgConfig).host;
294
293
  const targetFile = args.file_path ?? DEFAULT_CONFIG_FILE;
295
294
  process.stdout.write(`${chalk.yellow(chalk.bold(figures.arrowRight))} Generating configuration file for website with domain: ${chalk.yellow(siteHost)}\n`);
296
- let response = await cgFetch(new URL('/content/v2', cgConfig.gateway), { method: "POST", body: JSON.stringify(siteQuery(siteHost)) });
297
- if (!response.ok) {
295
+ const channelRepo = new ChannelRepository(cgConfig);
296
+ let channel = null;
297
+ try {
298
+ channel = await channelRepo.getByDomain(siteHost, false);
299
+ }
300
+ catch (e) {
301
+ if (args.verbose ?? false) {
302
+ process.stderr.write(chalk.redBright(chalk.bold(figures.cross) + " " + (new String(e))) + "\n");
303
+ }
298
304
  process.stdout.write(chalk.redBright(chalk.bold(figures.cross) + " Failed loading website data"));
299
305
  process.exitCode = 1;
300
306
  return;
301
307
  }
302
- let responseBody = await response.json();
303
- if ((responseBody.data?.SiteDefinition?.items?.length ?? 0) < 1) {
304
- process.stdout.write(`${chalk.red(chalk.bold(figures.bullet))} Domain not found, falling back to match-all domain: ${chalk.yellow("*")}\n`);
305
- response = await cgFetch(new URL('/content/v2', cgConfig.gateway), { method: "POST", body: JSON.stringify(siteQuery("*")) });
306
- if (!response.ok) {
308
+ if (!channel) {
309
+ try {
310
+ process.stdout.write(`${chalk.red(chalk.bold(figures.bullet))} Domain not found, falling back to match-all domain: ${chalk.yellow("*")}\n`);
311
+ channel = await channelRepo.getByDomain(siteHost, true);
312
+ }
313
+ catch (e) {
314
+ if (args.verbose ?? false) {
315
+ process.stderr.write(chalk.redBright(chalk.bold(figures.cross) + " " + (new String(e))) + "\n");
316
+ }
307
317
  process.stdout.write(chalk.redBright(chalk.bold(figures.cross) + " Failed loading website data"));
308
318
  process.exitCode = 1;
309
319
  return;
310
320
  }
311
- responseBody = await response.json();
312
321
  }
313
- if ((responseBody.data?.SiteDefinition?.items?.length ?? 0) < 1) {
322
+ if (!channel || channel == null) {
314
323
  process.stdout.write(chalk.redBright(`${chalk.bold(figures.cross)} No website defintion found for host ${siteHost}`) + "\n");
315
324
  process.exitCode = 1;
316
325
  return;
317
326
  }
318
- if ((responseBody.data?.SiteDefinition?.items?.length ?? 0) > 1) {
319
- process.stdout.write(chalk.redBright(`${chalk.bold(figures.cross)} Multiple website defintion found for host ${siteHost}, please correct your CMS configuration`) + "\n");
320
- process.exitCode = 1;
321
- return;
322
- }
323
327
  process.stdout.write(`${chalk.yellow(chalk.bold(figures.arrowRight))} Loaded website data, generating TypeScript code.\n`);
324
- const siteDefinition = responseBody.data.SiteDefinition.items[0];
325
- siteDefinition.domains = (siteDefinition.domains ?? []).map((d) => {
326
- const def = {
327
- name: d.name,
328
- isPrimary: d.type == "Primary",
329
- isEdit: d.type == "Edit"
330
- };
331
- if (d.forLocale?.code)
332
- def.forLocale = d.forLocale?.code;
333
- return def;
334
- });
335
- siteDefinition.locales = (siteDefinition.locales ?? []).map((c) => {
336
- const loc = {
337
- code: c.code,
338
- slug: c.slug?.toLowerCase(),
339
- graphLocale: c.code.replace("-", "_"),
340
- isDefault: c.isDefault == true
341
- };
342
- return loc;
343
- });
328
+ const [siteDefinition, cms_url] = channel.asDataObject();
344
329
  const code = [
345
330
  '/**',
346
331
  ' * This file has been automatically generated, do not update manually',
347
332
  ' *',
348
- ' * Use yarn frontend-cli site-config to re-generate this file',
333
+ ' * Use yarn opti-graph config:create [file_path] to re-generate this file',
349
334
  ' */',
350
335
  'import { ChannelDefinition, type ChannelDefinitionData } from "@remkoj/optimizely-graph-client"',
351
336
  '',
352
337
  `const generated_data : ChannelDefinitionData = ${JSON.stringify(siteDefinition)};`,
353
338
  '',
354
- `export const SiteConfig = new ChannelDefinition(generated_data, "${cgConfig.dxp_url}")`,
339
+ `export const SiteConfig = new ChannelDefinition(generated_data, "${cms_url}")`,
355
340
  'export default SiteConfig'
356
341
  ];
357
342
  const filePath = path__default.join(process.cwd(), targetFile);
@@ -366,45 +351,158 @@ const createSiteConfigModule = {
366
351
  aliases: [],
367
352
  describe: "Generate a static site configuration file",
368
353
  };
369
- function siteQuery(site_url) {
370
- return {
371
- query: `query GetSiteConfig($domain: String!) {
372
- SiteDefinition (
373
- where: {
374
- _or: [
375
- { Hosts: { Name: { eq: $domain }} }
376
- ]
377
- }
378
- ) {
379
- items {
380
- id: Id
381
- name: Name,
382
- domains: Hosts {
383
- name: Name
384
- type: Type
385
- forLocale: Language {
386
- code: Name
387
- }
388
- }
389
- locales:Languages {
390
- code:Name
391
- slug:UrlSegment
392
- isDefault:IsMasterLanguage
393
- }
394
- content: ContentRoots {
395
- startPage: StartPage {
396
- id:Id,
397
- guidValue:GuidValue
398
- }
399
- }
400
- }
401
- }
402
- }`,
403
- variables: JSON.stringify({ domain: site_url })
404
- };
405
- }
406
354
 
407
- var commands = [publishToVercelModule$2, publishToVercelModule$1, publishToVercelModule, createSiteConfigModule];
355
+ const GraphSourceListCommand = {
356
+ command: ['source:list', 'sl'],
357
+ handler: async (args) => {
358
+ const cgConfig = getArgsConfig(args);
359
+ if (!cgConfig.app_key || !cgConfig.secret)
360
+ throw new Error("Make sure both the Optimizely Graph App Key & Secret have been defined");
361
+ const adminApi = createAdminApi(cgConfig);
362
+ try {
363
+ const currentSources = (await adminApi.definitionV3.getContentV3SourceHandler());
364
+ const sources = new Table({
365
+ head: [chalk.yellow(chalk.bold("ID")), chalk.yellow(chalk.bold("Label")), chalk.yellow(chalk.bold("Languages"))],
366
+ colWidths: [10, 50, 50]
367
+ });
368
+ for (const sourceDetails of currentSources) {
369
+ sources.push([sourceDetails.id, sourceDetails.label, sourceDetails.languages.join(', ')]);
370
+ }
371
+ process.stdout.write(sources.toString() + "\n");
372
+ process.stdout.write(chalk.green(chalk.bold(figures.tick + " Done")) + "\n");
373
+ }
374
+ catch (e) {
375
+ if (isApiError(e)) {
376
+ process.stderr.write(chalk.redBright(`${chalk.bold(figures.cross)} Optimizely Graph returned an error: HTTP ${e.status}: ${e.statusText}`) + "\n");
377
+ if (args.verbose)
378
+ console.error(chalk.redBright(JSON.stringify(e.body, undefined, 4)));
379
+ }
380
+ else {
381
+ process.stderr.write(chalk.redBright(`${chalk.bold(figures.cross)} Optimizely Graph returned an unknown error`) + "\n");
382
+ if (args.verbose)
383
+ console.error(chalk.redBright(e));
384
+ }
385
+ process.exitCode = 1;
386
+ return;
387
+ }
388
+ },
389
+ aliases: [],
390
+ describe: "List all content sources in Optimizely Graph",
391
+ };
392
+
393
+ const GraphSourceClearCommand = {
394
+ command: ['source:clear [sourceId]', 'sc [sourceId]'],
395
+ handler: async (args) => {
396
+ const cgConfig = getArgsConfig(args);
397
+ if (!cgConfig.app_key || !cgConfig.secret)
398
+ throw new Error("Make sure both the Optimizely Graph App Key & Secret have been defined");
399
+ const sourceId = args.sourceId;
400
+ if (!sourceId) {
401
+ process.stderr.write(chalk.redBright(`${chalk.bold(figures.cross)} Missing source ID, invoke with --help for more details`) + "\n");
402
+ return process.exit(1);
403
+ }
404
+ const adminApi = createAdminApi(cgConfig);
405
+ try {
406
+ process.stdout.write(`${chalk.yellow(chalk.bold(figures.arrowRight))} Loading content source: ${chalk.yellow(sourceId)}\n`);
407
+ const contentSource = (await adminApi.definitionV3.getContentV3SourceHandler(sourceId))[0];
408
+ if (!(contentSource && contentSource.id == sourceId)) {
409
+ throw new Error("An incorrect content source was returned by Optimizely Graph");
410
+ }
411
+ process.stdout.write(`${chalk.yellow(chalk.bold(figures.arrowRight))} Removing all content from ${chalk.yellow(contentSource.label)} (Languages: ${chalk.yellow(contentSource.languages.join(', '))})\n`);
412
+ await adminApi.definitionV2.deleteContentV2DataHandler(sourceId, contentSource.languages);
413
+ process.stdout.write(chalk.green(chalk.bold(figures.tick + " Done")) + "\n");
414
+ }
415
+ catch (e) {
416
+ if (isApiError(e)) {
417
+ if (e.status == 404) {
418
+ process.stderr.write(chalk.redBright(`${chalk.bold(figures.cross)} Optimizely Graph Source with ID ${sourceId} does not exist`) + "\n");
419
+ }
420
+ else {
421
+ process.stderr.write(chalk.redBright(`${chalk.bold(figures.cross)} Optimizely Graph returned an error: HTTP ${e.status}: ${e.statusText}`) + "\n");
422
+ }
423
+ if (args.verbose)
424
+ console.error(chalk.redBright(JSON.stringify(e.body, undefined, 4)));
425
+ }
426
+ else {
427
+ process.stderr.write(chalk.redBright(`${chalk.bold(figures.cross)} Optimizely Graph returned an unknown error`) + "\n");
428
+ if (args.verbose)
429
+ console.error(chalk.redBright(e));
430
+ }
431
+ process.exitCode = 1;
432
+ return;
433
+ }
434
+ },
435
+ aliases: [],
436
+ builder: (args) => {
437
+ args.positional('sourceId', { type: "string", describe: "The source to clear", demandOption: true });
438
+ return args;
439
+ },
440
+ describe: "Remove all data for the specified source",
441
+ };
442
+
443
+ const GraphSourceRemoveCommand = {
444
+ command: ['source:delete [sourceId]', 'sd [sourceId]'],
445
+ handler: async (args) => {
446
+ const cgConfig = getArgsConfig(args);
447
+ if (!cgConfig.app_key || !cgConfig.secret)
448
+ throw new Error("Make sure both the Optimizely Graph App Key & Secret have been defined");
449
+ const sourceId = args.sourceId;
450
+ if (!sourceId) {
451
+ process.stderr.write(chalk.redBright(`${chalk.bold(figures.cross)} Missing source ID, invoke with --help for more details`) + "\n");
452
+ return process.exit(1);
453
+ }
454
+ const adminApi = createAdminApi(cgConfig);
455
+ try {
456
+ process.stdout.write(`${chalk.yellow(chalk.bold(figures.arrowRight))} Loading content source: ${chalk.yellow(sourceId)}\n`);
457
+ const contentSource = (await adminApi.definitionV3.getContentV3SourceHandler(sourceId))[0];
458
+ if (!(contentSource && contentSource.id == sourceId)) {
459
+ throw new Error("An incorrect content source was returned by Optimizely Graph");
460
+ }
461
+ process.stdout.write(`${chalk.yellow(chalk.bold(figures.arrowRight))} Removing all content from ${chalk.yellow(contentSource.label)} (Languages: ${chalk.yellow(contentSource.languages.join(', '))})\n`);
462
+ await adminApi.definitionV2.deleteContentV2DataHandler(sourceId, contentSource.languages);
463
+ process.stdout.write(`${chalk.yellow(chalk.bold(figures.arrowRight))} Removing source ${chalk.yellow(contentSource.label)}\n`);
464
+ await adminApi.definitionV3.deleteContentV3SourceHandler(sourceId);
465
+ process.stdout.write(chalk.green(chalk.bold(figures.tick + " Done")) + "\n");
466
+ }
467
+ catch (e) {
468
+ if (isApiError(e)) {
469
+ if (e.status == 404) {
470
+ process.stderr.write(chalk.redBright(`${chalk.bold(figures.cross)} Optimizely Graph Source with ID ${sourceId} does not exist`) + "\n");
471
+ }
472
+ else {
473
+ process.stderr.write(chalk.redBright(`${chalk.bold(figures.cross)} Optimizely Graph returned an error: HTTP ${e.status}: ${e.statusText}`) + "\n");
474
+ }
475
+ if (args.verbose)
476
+ console.error(chalk.redBright(JSON.stringify(e.body, undefined, 4)));
477
+ }
478
+ else {
479
+ process.stderr.write(chalk.redBright(`${chalk.bold(figures.cross)} Optimizely Graph returned an unknown error`) + "\n");
480
+ if (args.verbose)
481
+ console.error(chalk.redBright(e));
482
+ }
483
+ process.exitCode = 1;
484
+ return;
485
+ }
486
+ },
487
+ aliases: [],
488
+ builder: (args) => {
489
+ args.positional('sourceId', { type: "string", describe: "The source to clear", demandOption: true });
490
+ return args;
491
+ },
492
+ describe: "Remove all data for the specified source",
493
+ };
494
+
495
+ var SourceModules = /*#__PURE__*/Object.freeze({
496
+ __proto__: null,
497
+ GraphSourceClearCommand: GraphSourceClearCommand,
498
+ GraphSourceListCommand: GraphSourceListCommand,
499
+ GraphSourceRemoveCommand: GraphSourceRemoveCommand
500
+ });
501
+
502
+ const modules = [publishToVercelModule$2, publishToVercelModule$1, publishToVercelModule, createSiteConfigModule];
503
+ for (const moduleName of Object.getOwnPropertyNames(SourceModules)) {
504
+ modules.push(SourceModules[moduleName]);
505
+ }
408
506
 
409
507
  var APP;
410
508
  (function (APP) {
@@ -412,5 +510,5 @@ var APP;
412
510
  APP["Version"] = "1.0.3";
413
511
  })(APP || (APP = {}));
414
512
  const app = createCliApp(APP.Script, APP.Version);
415
- app.command(commands);
513
+ app.command(modules);
416
514
  app.parse(process.argv.slice(2));
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "repository": "https://github.com/remkoj/optimizely-dxp-clients.git",
4
4
  "author": "Remko Jantzen <693172+remkoj@users.noreply.github.com>",
5
5
  "homepage": "https://github.com/remkoj/optimizely-dxp-clients",
6
- "version": "1.0.3",
6
+ "version": "2.0.0-pre1",
7
7
  "license": "Apache-2.0",
8
8
  "packageManager": "yarn@4.1.1",
9
9
  "type": "module",
@@ -27,19 +27,19 @@
27
27
  "bundle": "yarn rollup --config rollup.config.js"
28
28
  },
29
29
  "devDependencies": {
30
- "@remkoj/optimizely-graph-client": "1.0.3",
30
+ "@remkoj/optimizely-graph-client": "2.0.0-pre1",
31
31
  "@rollup/plugin-commonjs": "^25.0.7",
32
32
  "@rollup/plugin-json": "^6.1.0",
33
33
  "@rollup/pluginutils": "^5.1.0",
34
34
  "@types/crypto-js": "^4.2.2",
35
35
  "@types/glob": "^8.1.0",
36
- "@types/node": "^20.12.4",
36
+ "@types/node": "^20.12.7",
37
37
  "@types/source-map-support": "^0.5.10",
38
38
  "@types/yargs": "^17.0.32",
39
- "rollup": "^4.14.0",
39
+ "rollup": "^4.16.2",
40
40
  "source-map-support": "^0.5.21",
41
41
  "tslib": "^2.6.2",
42
- "typescript": "^5.4.3"
42
+ "typescript": "^5.4.5"
43
43
  },
44
44
  "dependencies": {
45
45
  "chalk": "^5.3.0",
@@ -50,6 +50,7 @@
50
50
  "yargs": "^17.7.2"
51
51
  },
52
52
  "peerDependencies": {
53
- "@remkoj/optimizely-graph-client": "1.0.3"
54
- }
53
+ "@remkoj/optimizely-graph-client": "2.0.0-pre1"
54
+ },
55
+ "stableVersion": "1.0.4"
55
56
  }