@wix/web50-cli 0.1.0 → 0.1.1

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 (122) hide show
  1. package/dist/cjs/auth/deviceFlow.js +99 -13
  2. package/dist/cjs/auth/deviceFlow.js.map +1 -1
  3. package/dist/cjs/auth/index.js +65 -12
  4. package/dist/cjs/auth/index.js.map +1 -1
  5. package/dist/cjs/auth/secretStore.js.map +1 -1
  6. package/dist/cjs/cli.js +29 -1
  7. package/dist/cjs/cli.js.map +1 -1
  8. package/dist/cjs/commands/bundle.js +95 -0
  9. package/dist/cjs/commands/bundle.js.map +1 -0
  10. package/dist/cjs/commands/conversation.js +50 -0
  11. package/dist/cjs/commands/conversation.js.map +1 -0
  12. package/dist/cjs/commands/conversationWizard.js +526 -0
  13. package/dist/cjs/commands/conversationWizard.js.map +1 -0
  14. package/dist/cjs/commands/deploy.js +192 -0
  15. package/dist/cjs/commands/deploy.js.map +1 -0
  16. package/dist/cjs/commands/embed.js +118 -0
  17. package/dist/cjs/commands/embed.js.map +1 -0
  18. package/dist/cjs/commands/getClientId.js +60 -0
  19. package/dist/cjs/commands/getClientId.js.map +1 -0
  20. package/dist/cjs/commands/init.js +31 -26
  21. package/dist/cjs/commands/init.js.map +1 -1
  22. package/dist/cjs/commands/instructions.js +360 -0
  23. package/dist/cjs/commands/instructions.js.map +1 -0
  24. package/dist/cjs/commands/login.js +59 -4
  25. package/dist/cjs/commands/login.js.map +1 -1
  26. package/dist/cjs/commands/logout.js +16 -0
  27. package/dist/cjs/commands/logout.js.map +1 -0
  28. package/dist/cjs/commands/serve.js +122 -0
  29. package/dist/cjs/commands/serve.js.map +1 -0
  30. package/dist/cjs/commands/storybook.js +102 -0
  31. package/dist/cjs/commands/storybook.js.map +1 -0
  32. package/dist/cjs/commands/validate.js +266 -18
  33. package/dist/cjs/commands/validate.js.map +1 -1
  34. package/dist/cjs/commands/whoami.js +48 -0
  35. package/dist/cjs/commands/whoami.js.map +1 -0
  36. package/dist/cjs/utils/print.js +12 -0
  37. package/dist/cjs/utils/print.js.map +1 -1
  38. package/dist/cjs/utils/project.js +11 -0
  39. package/dist/cjs/utils/project.js.map +1 -1
  40. package/dist/cjs/utils/wixApi.js +55 -0
  41. package/dist/cjs/utils/wixApi.js.map +1 -0
  42. package/dist/esm/auth/deviceFlow.js +106 -13
  43. package/dist/esm/auth/deviceFlow.js.map +1 -1
  44. package/dist/esm/auth/index.js +71 -13
  45. package/dist/esm/auth/index.js.map +1 -1
  46. package/dist/esm/auth/secretStore.js.map +1 -1
  47. package/dist/esm/cli.js +29 -1
  48. package/dist/esm/cli.js.map +1 -1
  49. package/dist/esm/commands/bundle.js +92 -0
  50. package/dist/esm/commands/bundle.js.map +1 -0
  51. package/dist/esm/commands/conversation.js +44 -0
  52. package/dist/esm/commands/conversation.js.map +1 -0
  53. package/dist/esm/commands/conversationWizard.js +527 -0
  54. package/dist/esm/commands/conversationWizard.js.map +1 -0
  55. package/dist/esm/commands/deploy.js +194 -0
  56. package/dist/esm/commands/deploy.js.map +1 -0
  57. package/dist/esm/commands/embed.js +112 -0
  58. package/dist/esm/commands/embed.js.map +1 -0
  59. package/dist/esm/commands/getClientId.js +56 -0
  60. package/dist/esm/commands/getClientId.js.map +1 -0
  61. package/dist/esm/commands/init.js +32 -27
  62. package/dist/esm/commands/init.js.map +1 -1
  63. package/dist/esm/commands/instructions.js +360 -0
  64. package/dist/esm/commands/instructions.js.map +1 -0
  65. package/dist/esm/commands/login.js +62 -6
  66. package/dist/esm/commands/login.js.map +1 -1
  67. package/dist/esm/commands/logout.js +12 -0
  68. package/dist/esm/commands/logout.js.map +1 -0
  69. package/dist/esm/commands/serve.js +117 -0
  70. package/dist/esm/commands/serve.js.map +1 -0
  71. package/dist/esm/commands/storybook.js +97 -0
  72. package/dist/esm/commands/storybook.js.map +1 -0
  73. package/dist/esm/commands/validate.js +269 -19
  74. package/dist/esm/commands/validate.js.map +1 -1
  75. package/dist/esm/commands/whoami.js +44 -0
  76. package/dist/esm/commands/whoami.js.map +1 -0
  77. package/dist/esm/utils/print.js +10 -0
  78. package/dist/esm/utils/print.js.map +1 -1
  79. package/dist/esm/utils/project.js +8 -0
  80. package/dist/esm/utils/project.js.map +1 -1
  81. package/dist/esm/utils/wixApi.js +51 -0
  82. package/dist/esm/utils/wixApi.js.map +1 -0
  83. package/dist/types/auth/deviceFlow.d.ts +3 -1
  84. package/dist/types/auth/deviceFlow.d.ts.map +1 -1
  85. package/dist/types/auth/index.d.ts +5 -1
  86. package/dist/types/auth/index.d.ts.map +1 -1
  87. package/dist/types/auth/secretStore.d.ts +2 -0
  88. package/dist/types/auth/secretStore.d.ts.map +1 -1
  89. package/dist/types/commands/bundle.d.ts +10 -0
  90. package/dist/types/commands/bundle.d.ts.map +1 -0
  91. package/dist/types/commands/conversation.d.ts +3 -0
  92. package/dist/types/commands/conversation.d.ts.map +1 -0
  93. package/dist/types/commands/conversationWizard.d.ts +3 -0
  94. package/dist/types/commands/conversationWizard.d.ts.map +1 -0
  95. package/dist/types/commands/deploy.d.ts +3 -0
  96. package/dist/types/commands/deploy.d.ts.map +1 -0
  97. package/dist/types/commands/embed.d.ts +3 -0
  98. package/dist/types/commands/embed.d.ts.map +1 -0
  99. package/dist/types/commands/getClientId.d.ts +3 -0
  100. package/dist/types/commands/getClientId.d.ts.map +1 -0
  101. package/dist/types/commands/init.d.ts.map +1 -1
  102. package/dist/types/commands/instructions.d.ts +3 -0
  103. package/dist/types/commands/instructions.d.ts.map +1 -0
  104. package/dist/types/commands/login.d.ts.map +1 -1
  105. package/dist/types/commands/logout.d.ts +3 -0
  106. package/dist/types/commands/logout.d.ts.map +1 -0
  107. package/dist/types/commands/serve.d.ts +3 -0
  108. package/dist/types/commands/serve.d.ts.map +1 -0
  109. package/dist/types/commands/storybook.d.ts +3 -0
  110. package/dist/types/commands/storybook.d.ts.map +1 -0
  111. package/dist/types/commands/validate.d.ts +5 -0
  112. package/dist/types/commands/validate.d.ts.map +1 -1
  113. package/dist/types/commands/whoami.d.ts +3 -0
  114. package/dist/types/commands/whoami.d.ts.map +1 -0
  115. package/dist/types/utils/print.d.ts +3 -0
  116. package/dist/types/utils/print.d.ts.map +1 -1
  117. package/dist/types/utils/project.d.ts +10 -0
  118. package/dist/types/utils/project.d.ts.map +1 -1
  119. package/dist/types/utils/wixApi.d.ts +9 -0
  120. package/dist/types/utils/wixApi.d.ts.map +1 -0
  121. package/package.json +5 -5
  122. package/defaults/package.json +0 -42
@@ -4,7 +4,9 @@ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefau
4
4
  exports.__esModule = true;
5
5
  exports.error = error;
6
6
  exports.info = info;
7
+ exports.isJsonMode = isJsonMode;
7
8
  exports.spinner = spinner;
9
+ exports.step = step;
8
10
  exports.success = success;
9
11
  exports.warn = warn;
10
12
  var _chalk = _interopRequireDefault(require("chalk"));
@@ -24,4 +26,14 @@ function warn(msg) {
24
26
  function spinner(msg) {
25
27
  return (0, _ora.default)(msg).start();
26
28
  }
29
+ function step(n, total, label) {
30
+ console.log('');
31
+ console.log(_chalk.default.bold.cyan(` Step ${n}/${total} ${label}`));
32
+ console.log(_chalk.default.dim(` ${'─'.repeat(40)}`));
33
+ }
34
+
35
+ /** Returns true when the caller passed --json (or set WEB5_JSON_MODE=1). */
36
+ function isJsonMode() {
37
+ return process.env.WEB5_JSON_MODE === '1';
38
+ }
27
39
  //# sourceMappingURL=print.js.map
@@ -1 +1 @@
1
- {"version":3,"names":["_chalk","_interopRequireDefault","require","_ora","success","msg","console","log","chalk","green","error","process","stderr","write","red","info","dim","warn","yellow","spinner","ora","start"],"sources":["../../../src/utils/print.ts"],"sourcesContent":["import chalk from 'chalk';\nimport ora from 'ora';\nimport type { Ora } from 'ora';\n\nexport function success(msg: string): void {\n console.log(chalk.green(`\\u2714 ${msg}`));\n}\n\nexport function error(msg: string): void {\n process.stderr.write(chalk.red(`\\u2716 ${msg}\\n`));\n}\n\nexport function info(msg: string): void {\n console.log(chalk.dim(` ${msg}`));\n}\n\nexport function warn(msg: string): void {\n console.log(chalk.yellow(`\\u26a0 ${msg}`));\n}\n\nexport function spinner(msg: string): Ora {\n return ora(msg).start();\n}\n"],"mappings":";;;;;;;;;AAAA,IAAAA,MAAA,GAAAC,sBAAA,CAAAC,OAAA;AACA,IAAAC,IAAA,GAAAF,sBAAA,CAAAC,OAAA;AAGO,SAASE,OAAOA,CAACC,GAAW,EAAQ;EACzCC,OAAO,CAACC,GAAG,CAACC,cAAK,CAACC,KAAK,CAAC,WAAWJ,GAAG,EAAE,CAAC,CAAC;AAC5C;AAEO,SAASK,KAAKA,CAACL,GAAW,EAAQ;EACvCM,OAAO,CAACC,MAAM,CAACC,KAAK,CAACL,cAAK,CAACM,GAAG,CAAC,WAAWT,GAAG,IAAI,CAAC,CAAC;AACrD;AAEO,SAASU,IAAIA,CAACV,GAAW,EAAQ;EACtCC,OAAO,CAACC,GAAG,CAACC,cAAK,CAACQ,GAAG,CAAC,MAAMX,GAAG,EAAE,CAAC,CAAC;AACrC;AAEO,SAASY,IAAIA,CAACZ,GAAW,EAAQ;EACtCC,OAAO,CAACC,GAAG,CAACC,cAAK,CAACU,MAAM,CAAC,WAAWb,GAAG,EAAE,CAAC,CAAC;AAC7C;AAEO,SAASc,OAAOA,CAACd,GAAW,EAAO;EACxC,OAAO,IAAAe,YAAG,EAACf,GAAG,CAAC,CAACgB,KAAK,CAAC,CAAC;AACzB","ignoreList":[]}
1
+ {"version":3,"names":["_chalk","_interopRequireDefault","require","_ora","success","msg","console","log","chalk","green","error","process","stderr","write","red","info","dim","warn","yellow","spinner","ora","start","step","n","total","label","bold","cyan","repeat","isJsonMode","env","WEB5_JSON_MODE"],"sources":["../../../src/utils/print.ts"],"sourcesContent":["import chalk from 'chalk';\nimport ora from 'ora';\nimport type { Ora } from 'ora';\n\nexport function success(msg: string): void {\n console.log(chalk.green(`\\u2714 ${msg}`));\n}\n\nexport function error(msg: string): void {\n process.stderr.write(chalk.red(`\\u2716 ${msg}\\n`));\n}\n\nexport function info(msg: string): void {\n console.log(chalk.dim(` ${msg}`));\n}\n\nexport function warn(msg: string): void {\n console.log(chalk.yellow(`\\u26a0 ${msg}`));\n}\n\nexport function spinner(msg: string): Ora {\n return ora(msg).start();\n}\n\nexport function step(n: number, total: number, label: string): void {\n console.log('');\n console.log(chalk.bold.cyan(` Step ${n}/${total} ${label}`));\n console.log(chalk.dim(` ${'─'.repeat(40)}`));\n}\n\n/** Returns true when the caller passed --json (or set WEB5_JSON_MODE=1). */\nexport function isJsonMode(): boolean {\n return process.env.WEB5_JSON_MODE === '1';\n}\n"],"mappings":";;;;;;;;;;;AAAA,IAAAA,MAAA,GAAAC,sBAAA,CAAAC,OAAA;AACA,IAAAC,IAAA,GAAAF,sBAAA,CAAAC,OAAA;AAGO,SAASE,OAAOA,CAACC,GAAW,EAAQ;EACzCC,OAAO,CAACC,GAAG,CAACC,cAAK,CAACC,KAAK,CAAC,WAAWJ,GAAG,EAAE,CAAC,CAAC;AAC5C;AAEO,SAASK,KAAKA,CAACL,GAAW,EAAQ;EACvCM,OAAO,CAACC,MAAM,CAACC,KAAK,CAACL,cAAK,CAACM,GAAG,CAAC,WAAWT,GAAG,IAAI,CAAC,CAAC;AACrD;AAEO,SAASU,IAAIA,CAACV,GAAW,EAAQ;EACtCC,OAAO,CAACC,GAAG,CAACC,cAAK,CAACQ,GAAG,CAAC,MAAMX,GAAG,EAAE,CAAC,CAAC;AACrC;AAEO,SAASY,IAAIA,CAACZ,GAAW,EAAQ;EACtCC,OAAO,CAACC,GAAG,CAACC,cAAK,CAACU,MAAM,CAAC,WAAWb,GAAG,EAAE,CAAC,CAAC;AAC7C;AAEO,SAASc,OAAOA,CAACd,GAAW,EAAO;EACxC,OAAO,IAAAe,YAAG,EAACf,GAAG,CAAC,CAACgB,KAAK,CAAC,CAAC;AACzB;AAEO,SAASC,IAAIA,CAACC,CAAS,EAAEC,KAAa,EAAEC,KAAa,EAAQ;EAClEnB,OAAO,CAACC,GAAG,CAAC,EAAE,CAAC;EACfD,OAAO,CAACC,GAAG,CAACC,cAAK,CAACkB,IAAI,CAACC,IAAI,CAAC,UAAUJ,CAAC,IAAIC,KAAK,KAAKC,KAAK,EAAE,CAAC,CAAC;EAC9DnB,OAAO,CAACC,GAAG,CAACC,cAAK,CAACQ,GAAG,CAAC,KAAK,GAAG,CAACY,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;AAC/C;;AAEA;AACO,SAASC,UAAUA,CAAA,EAAY;EACpC,OAAOlB,OAAO,CAACmB,GAAG,CAACC,cAAc,KAAK,GAAG;AAC3C","ignoreList":[]}
@@ -2,9 +2,20 @@
2
2
 
3
3
  exports.__esModule = true;
4
4
  exports.findProjectRoot = findProjectRoot;
5
+ exports.readConfig = readConfig;
6
+ exports.writeConfig = writeConfig;
5
7
  var fs = _interopRequireWildcard(require("fs"));
6
8
  var path = _interopRequireWildcard(require("path"));
7
9
  function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
10
+ function readConfig(root) {
11
+ const configPath = path.join(root, 'web5.config.json');
12
+ return JSON.parse(fs.readFileSync(configPath, 'utf8'));
13
+ }
14
+ function writeConfig(root, config) {
15
+ const configPath = path.join(root, 'web5.config.json');
16
+ fs.writeFileSync(configPath, JSON.stringify(config, null, 2) + '\n', 'utf8');
17
+ }
18
+
8
19
  /**
9
20
  * Walk up from startDir until we find a directory containing web5.config.json.
10
21
  * Returns that directory, or null if none found.
@@ -1 +1 @@
1
- {"version":3,"names":["fs","_interopRequireWildcard","require","path","e","t","WeakMap","r","n","__esModule","o","i","f","__proto__","default","has","get","set","hasOwnProperty","call","Object","defineProperty","getOwnPropertyDescriptor","findProjectRoot","startDir","current","parent","dirname","existsSync","join"],"sources":["../../../src/utils/project.ts"],"sourcesContent":["import * as fs from 'fs';\nimport * as path from 'path';\n\n/**\n * Walk up from startDir until we find a directory containing web5.config.json.\n * Returns that directory, or null if none found.\n */\nexport function findProjectRoot(startDir: string): string | null {\n let current = startDir;\n let parent = path.dirname(current);\n while (current !== parent) {\n if (fs.existsSync(path.join(current, 'web5.config.json'))) {\n return current;\n }\n current = parent;\n parent = path.dirname(current);\n }\n if (fs.existsSync(path.join(current, 'web5.config.json'))) {\n return current;\n }\n return null;\n}\n"],"mappings":";;;;AAAA,IAAAA,EAAA,GAAAC,uBAAA,CAAAC,OAAA;AACA,IAAAC,IAAA,GAAAF,uBAAA,CAAAC,OAAA;AAA6B,SAAAD,wBAAAG,CAAA,EAAAC,CAAA,6BAAAC,OAAA,MAAAC,CAAA,OAAAD,OAAA,IAAAE,CAAA,OAAAF,OAAA,YAAAL,uBAAA,YAAAA,CAAAG,CAAA,EAAAC,CAAA,SAAAA,CAAA,IAAAD,CAAA,IAAAA,CAAA,CAAAK,UAAA,SAAAL,CAAA,MAAAM,CAAA,EAAAC,CAAA,EAAAC,CAAA,KAAAC,SAAA,QAAAC,OAAA,EAAAV,CAAA,iBAAAA,CAAA,uBAAAA,CAAA,yBAAAA,CAAA,SAAAQ,CAAA,MAAAF,CAAA,GAAAL,CAAA,GAAAG,CAAA,GAAAD,CAAA,QAAAG,CAAA,CAAAK,GAAA,CAAAX,CAAA,UAAAM,CAAA,CAAAM,GAAA,CAAAZ,CAAA,GAAAM,CAAA,CAAAO,GAAA,CAAAb,CAAA,EAAAQ,CAAA,gBAAAP,CAAA,IAAAD,CAAA,gBAAAC,CAAA,OAAAa,cAAA,CAAAC,IAAA,CAAAf,CAAA,EAAAC,CAAA,OAAAM,CAAA,IAAAD,CAAA,GAAAU,MAAA,CAAAC,cAAA,KAAAD,MAAA,CAAAE,wBAAA,CAAAlB,CAAA,EAAAC,CAAA,OAAAM,CAAA,CAAAK,GAAA,IAAAL,CAAA,CAAAM,GAAA,IAAAP,CAAA,CAAAE,CAAA,EAAAP,CAAA,EAAAM,CAAA,IAAAC,CAAA,CAAAP,CAAA,IAAAD,CAAA,CAAAC,CAAA,WAAAO,CAAA,KAAAR,CAAA,EAAAC,CAAA;AAE7B;AACA;AACA;AACA;AACO,SAASkB,eAAeA,CAACC,QAAgB,EAAiB;EAC/D,IAAIC,OAAO,GAAGD,QAAQ;EACtB,IAAIE,MAAM,GAAGvB,IAAI,CAACwB,OAAO,CAACF,OAAO,CAAC;EAClC,OAAOA,OAAO,KAAKC,MAAM,EAAE;IACzB,IAAI1B,EAAE,CAAC4B,UAAU,CAACzB,IAAI,CAAC0B,IAAI,CAACJ,OAAO,EAAE,kBAAkB,CAAC,CAAC,EAAE;MACzD,OAAOA,OAAO;IAChB;IACAA,OAAO,GAAGC,MAAM;IAChBA,MAAM,GAAGvB,IAAI,CAACwB,OAAO,CAACF,OAAO,CAAC;EAChC;EACA,IAAIzB,EAAE,CAAC4B,UAAU,CAACzB,IAAI,CAAC0B,IAAI,CAACJ,OAAO,EAAE,kBAAkB,CAAC,CAAC,EAAE;IACzD,OAAOA,OAAO;EAChB;EACA,OAAO,IAAI;AACb","ignoreList":[]}
1
+ {"version":3,"names":["fs","_interopRequireWildcard","require","path","e","t","WeakMap","r","n","__esModule","o","i","f","__proto__","default","has","get","set","hasOwnProperty","call","Object","defineProperty","getOwnPropertyDescriptor","readConfig","root","configPath","join","JSON","parse","readFileSync","writeConfig","config","writeFileSync","stringify","findProjectRoot","startDir","current","parent","dirname","existsSync"],"sources":["../../../src/utils/project.ts"],"sourcesContent":["import * as fs from 'fs';\nimport * as path from 'path';\n\nexport interface Web5Config {\n $schema?: string;\n packageName?: string;\n displayName?: string;\n msid?: string;\n clientId?: string;\n [key: string]: unknown;\n}\n\nexport function readConfig(root: string): Web5Config {\n const configPath = path.join(root, 'web5.config.json');\n return JSON.parse(fs.readFileSync(configPath, 'utf8')) as Web5Config;\n}\n\nexport function writeConfig(root: string, config: Web5Config): void {\n const configPath = path.join(root, 'web5.config.json');\n fs.writeFileSync(configPath, JSON.stringify(config, null, 2) + '\\n', 'utf8');\n}\n\n/**\n * Walk up from startDir until we find a directory containing web5.config.json.\n * Returns that directory, or null if none found.\n */\nexport function findProjectRoot(startDir: string): string | null {\n let current = startDir;\n let parent = path.dirname(current);\n while (current !== parent) {\n if (fs.existsSync(path.join(current, 'web5.config.json'))) {\n return current;\n }\n current = parent;\n parent = path.dirname(current);\n }\n if (fs.existsSync(path.join(current, 'web5.config.json'))) {\n return current;\n }\n return null;\n}\n"],"mappings":";;;;;;AAAA,IAAAA,EAAA,GAAAC,uBAAA,CAAAC,OAAA;AACA,IAAAC,IAAA,GAAAF,uBAAA,CAAAC,OAAA;AAA6B,SAAAD,wBAAAG,CAAA,EAAAC,CAAA,6BAAAC,OAAA,MAAAC,CAAA,OAAAD,OAAA,IAAAE,CAAA,OAAAF,OAAA,YAAAL,uBAAA,YAAAA,CAAAG,CAAA,EAAAC,CAAA,SAAAA,CAAA,IAAAD,CAAA,IAAAA,CAAA,CAAAK,UAAA,SAAAL,CAAA,MAAAM,CAAA,EAAAC,CAAA,EAAAC,CAAA,KAAAC,SAAA,QAAAC,OAAA,EAAAV,CAAA,iBAAAA,CAAA,uBAAAA,CAAA,yBAAAA,CAAA,SAAAQ,CAAA,MAAAF,CAAA,GAAAL,CAAA,GAAAG,CAAA,GAAAD,CAAA,QAAAG,CAAA,CAAAK,GAAA,CAAAX,CAAA,UAAAM,CAAA,CAAAM,GAAA,CAAAZ,CAAA,GAAAM,CAAA,CAAAO,GAAA,CAAAb,CAAA,EAAAQ,CAAA,gBAAAP,CAAA,IAAAD,CAAA,gBAAAC,CAAA,OAAAa,cAAA,CAAAC,IAAA,CAAAf,CAAA,EAAAC,CAAA,OAAAM,CAAA,IAAAD,CAAA,GAAAU,MAAA,CAAAC,cAAA,KAAAD,MAAA,CAAAE,wBAAA,CAAAlB,CAAA,EAAAC,CAAA,OAAAM,CAAA,CAAAK,GAAA,IAAAL,CAAA,CAAAM,GAAA,IAAAP,CAAA,CAAAE,CAAA,EAAAP,CAAA,EAAAM,CAAA,IAAAC,CAAA,CAAAP,CAAA,IAAAD,CAAA,CAAAC,CAAA,WAAAO,CAAA,KAAAR,CAAA,EAAAC,CAAA;AAWtB,SAASkB,UAAUA,CAACC,IAAY,EAAc;EACnD,MAAMC,UAAU,GAAGtB,IAAI,CAACuB,IAAI,CAACF,IAAI,EAAE,kBAAkB,CAAC;EACtD,OAAOG,IAAI,CAACC,KAAK,CAAC5B,EAAE,CAAC6B,YAAY,CAACJ,UAAU,EAAE,MAAM,CAAC,CAAC;AACxD;AAEO,SAASK,WAAWA,CAACN,IAAY,EAAEO,MAAkB,EAAQ;EAClE,MAAMN,UAAU,GAAGtB,IAAI,CAACuB,IAAI,CAACF,IAAI,EAAE,kBAAkB,CAAC;EACtDxB,EAAE,CAACgC,aAAa,CAACP,UAAU,EAAEE,IAAI,CAACM,SAAS,CAACF,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,EAAE,MAAM,CAAC;AAC9E;;AAEA;AACA;AACA;AACA;AACO,SAASG,eAAeA,CAACC,QAAgB,EAAiB;EAC/D,IAAIC,OAAO,GAAGD,QAAQ;EACtB,IAAIE,MAAM,GAAGlC,IAAI,CAACmC,OAAO,CAACF,OAAO,CAAC;EAClC,OAAOA,OAAO,KAAKC,MAAM,EAAE;IACzB,IAAIrC,EAAE,CAACuC,UAAU,CAACpC,IAAI,CAACuB,IAAI,CAACU,OAAO,EAAE,kBAAkB,CAAC,CAAC,EAAE;MACzD,OAAOA,OAAO;IAChB;IACAA,OAAO,GAAGC,MAAM;IAChBA,MAAM,GAAGlC,IAAI,CAACmC,OAAO,CAACF,OAAO,CAAC;EAChC;EACA,IAAIpC,EAAE,CAACuC,UAAU,CAACpC,IAAI,CAACuB,IAAI,CAACU,OAAO,EAAE,kBAAkB,CAAC,CAAC,EAAE;IACzD,OAAOA,OAAO;EAChB;EACA,OAAO,IAAI;AACb","ignoreList":[]}
@@ -0,0 +1,55 @@
1
+ "use strict";
2
+
3
+ exports.__esModule = true;
4
+ exports.wixRequest = wixRequest;
5
+ var _auth = require("../auth");
6
+ const BASE_URL = 'https://www.wixapis.com';
7
+ async function wixRequest(options) {
8
+ const {
9
+ path,
10
+ method = 'GET',
11
+ params,
12
+ body,
13
+ verbose = false
14
+ } = options;
15
+ const token = await (0, _auth.getToken)();
16
+ if (!token) {
17
+ throw new Error('Not authenticated. Run `web5 login` first.');
18
+ }
19
+ const url = new URL(`${BASE_URL}${path}`);
20
+ if (params) {
21
+ for (const [key, value] of Object.entries(params)) {
22
+ url.searchParams.set(key, value);
23
+ }
24
+ }
25
+ if (verbose) {
26
+ console.error(`[LOG] ${method} ${url.toString()}`);
27
+ if (body !== undefined) {
28
+ console.error(`[LOG] body: ${JSON.stringify(body)}`);
29
+ }
30
+ }
31
+ const res = await fetch(url.toString(), {
32
+ method,
33
+ headers: {
34
+ Authorization: `Bearer ${token}`,
35
+ 'Content-Type': 'application/json'
36
+ },
37
+ ...(body !== undefined ? {
38
+ body: JSON.stringify(body)
39
+ } : {})
40
+ });
41
+ const text = await res.text();
42
+ if (verbose) {
43
+ console.error(`[LOG] HTTP ${res.status} ${res.statusText}`);
44
+ console.error(`[LOG] response: ${text}`);
45
+ }
46
+ if (!text) {
47
+ throw new Error(`Empty response from ${method} ${path} (HTTP ${res.status})`);
48
+ }
49
+ try {
50
+ return JSON.parse(text);
51
+ } catch {
52
+ throw new Error(`Invalid JSON from ${method} ${path} (HTTP ${res.status}): ${text.slice(0, 200)}`);
53
+ }
54
+ }
55
+ //# sourceMappingURL=wixApi.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["_auth","require","BASE_URL","wixRequest","options","path","method","params","body","verbose","token","getToken","Error","url","URL","key","value","Object","entries","searchParams","set","console","error","toString","undefined","JSON","stringify","res","fetch","headers","Authorization","text","status","statusText","parse","slice"],"sources":["../../../src/utils/wixApi.ts"],"sourcesContent":["import { getToken } from '../auth';\n\nconst BASE_URL = 'https://www.wixapis.com';\n\nexport interface WixRequestOptions {\n path: string;\n method?: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';\n params?: Record<string, string>;\n body?: unknown;\n verbose?: boolean;\n}\n\nexport async function wixRequest<T = unknown>(\n options: WixRequestOptions,\n): Promise<T> {\n const { path, method = 'GET', params, body, verbose = false } = options;\n\n const token = await getToken();\n if (!token) {\n throw new Error('Not authenticated. Run `web5 login` first.');\n }\n\n const url = new URL(`${BASE_URL}${path}`);\n if (params) {\n for (const [key, value] of Object.entries(params)) {\n url.searchParams.set(key, value);\n }\n }\n\n if (verbose) {\n console.error(`[LOG] ${method} ${url.toString()}`);\n if (body !== undefined) {\n console.error(`[LOG] body: ${JSON.stringify(body)}`);\n }\n }\n\n const res = await fetch(url.toString(), {\n method,\n headers: {\n Authorization: `Bearer ${token}`,\n 'Content-Type': 'application/json',\n },\n ...(body !== undefined ? { body: JSON.stringify(body) } : {}),\n });\n\n const text = await res.text();\n\n if (verbose) {\n console.error(`[LOG] HTTP ${res.status} ${res.statusText}`);\n console.error(`[LOG] response: ${text}`);\n }\n\n if (!text) {\n throw new Error(\n `Empty response from ${method} ${path} (HTTP ${res.status})`,\n );\n }\n\n try {\n return JSON.parse(text) as T;\n } catch {\n throw new Error(\n `Invalid JSON from ${method} ${path} (HTTP ${res.status}): ${text.slice(\n 0,\n 200,\n )}`,\n );\n }\n}\n"],"mappings":";;;;AAAA,IAAAA,KAAA,GAAAC,OAAA;AAEA,MAAMC,QAAQ,GAAG,yBAAyB;AAUnC,eAAeC,UAAUA,CAC9BC,OAA0B,EACd;EACZ,MAAM;IAAEC,IAAI;IAAEC,MAAM,GAAG,KAAK;IAAEC,MAAM;IAAEC,IAAI;IAAEC,OAAO,GAAG;EAAM,CAAC,GAAGL,OAAO;EAEvE,MAAMM,KAAK,GAAG,MAAM,IAAAC,cAAQ,EAAC,CAAC;EAC9B,IAAI,CAACD,KAAK,EAAE;IACV,MAAM,IAAIE,KAAK,CAAC,4CAA4C,CAAC;EAC/D;EAEA,MAAMC,GAAG,GAAG,IAAIC,GAAG,CAAC,GAAGZ,QAAQ,GAAGG,IAAI,EAAE,CAAC;EACzC,IAAIE,MAAM,EAAE;IACV,KAAK,MAAM,CAACQ,GAAG,EAAEC,KAAK,CAAC,IAAIC,MAAM,CAACC,OAAO,CAACX,MAAM,CAAC,EAAE;MACjDM,GAAG,CAACM,YAAY,CAACC,GAAG,CAACL,GAAG,EAAEC,KAAK,CAAC;IAClC;EACF;EAEA,IAAIP,OAAO,EAAE;IACXY,OAAO,CAACC,KAAK,CAAC,SAAShB,MAAM,IAAIO,GAAG,CAACU,QAAQ,CAAC,CAAC,EAAE,CAAC;IAClD,IAAIf,IAAI,KAAKgB,SAAS,EAAE;MACtBH,OAAO,CAACC,KAAK,CAAC,eAAeG,IAAI,CAACC,SAAS,CAAClB,IAAI,CAAC,EAAE,CAAC;IACtD;EACF;EAEA,MAAMmB,GAAG,GAAG,MAAMC,KAAK,CAACf,GAAG,CAACU,QAAQ,CAAC,CAAC,EAAE;IACtCjB,MAAM;IACNuB,OAAO,EAAE;MACPC,aAAa,EAAE,UAAUpB,KAAK,EAAE;MAChC,cAAc,EAAE;IAClB,CAAC;IACD,IAAIF,IAAI,KAAKgB,SAAS,GAAG;MAAEhB,IAAI,EAAEiB,IAAI,CAACC,SAAS,CAAClB,IAAI;IAAE,CAAC,GAAG,CAAC,CAAC;EAC9D,CAAC,CAAC;EAEF,MAAMuB,IAAI,GAAG,MAAMJ,GAAG,CAACI,IAAI,CAAC,CAAC;EAE7B,IAAItB,OAAO,EAAE;IACXY,OAAO,CAACC,KAAK,CAAC,cAAcK,GAAG,CAACK,MAAM,IAAIL,GAAG,CAACM,UAAU,EAAE,CAAC;IAC3DZ,OAAO,CAACC,KAAK,CAAC,mBAAmBS,IAAI,EAAE,CAAC;EAC1C;EAEA,IAAI,CAACA,IAAI,EAAE;IACT,MAAM,IAAInB,KAAK,CACb,uBAAuBN,MAAM,IAAID,IAAI,UAAUsB,GAAG,CAACK,MAAM,GAC3D,CAAC;EACH;EAEA,IAAI;IACF,OAAOP,IAAI,CAACS,KAAK,CAACH,IAAI,CAAC;EACzB,CAAC,CAAC,MAAM;IACN,MAAM,IAAInB,KAAK,CACb,qBAAqBN,MAAM,IAAID,IAAI,UAAUsB,GAAG,CAACK,MAAM,MAAMD,IAAI,CAACI,KAAK,CACrE,CAAC,EACD,GACF,CAAC,EACH,CAAC;EACH;AACF","ignoreList":[]}
@@ -7,28 +7,65 @@ const DEVICE_CODE_URL = 'https://www.wixapis.com/oauth2/device/code';
7
7
  const TOKEN_URL = 'https://www.wixapis.com/oauth2/token';
8
8
  const POLL_INTERVAL_MS = 3000;
9
9
  const POLL_TIMEOUT_MS = 60_000;
10
+ let verboseMode = false;
11
+ function log() {
12
+ if (verboseMode) {
13
+ for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
14
+ args[_key] = arguments[_key];
15
+ }
16
+ console.log('[auth]', ...args);
17
+ }
18
+ }
10
19
  async function sleep(ms) {
11
20
  return new Promise(resolve => setTimeout(resolve, ms));
12
21
  }
13
22
  async function requestDeviceCode() {
14
- const res = await fetch(`${DEVICE_CODE_URL}?client_id=${CLIENT_ID}&scope=session_bound_access`);
23
+ const url = `${DEVICE_CODE_URL}?client_id=${CLIENT_ID}&scope=session_bound_access`;
24
+ log(`POST ${url}`);
25
+ const res = await fetch(url);
26
+ log(`Response: ${res.status} ${res.statusText}`);
15
27
  if (!res.ok) {
28
+ const body = await res.text().catch(() => '');
29
+ log(`Error body: ${body}`);
16
30
  throw new Error(`Device code request failed: ${res.status} ${res.statusText}`);
17
31
  }
18
- return res.json();
32
+ const data = await res.json();
33
+ log(`Device code response:`, JSON.stringify(data, null, 2));
34
+ return data;
19
35
  }
20
36
  async function pollToken(deviceCode) {
21
37
  const deadline = Date.now() + POLL_TIMEOUT_MS;
22
- const url = `${TOKEN_URL}` + `?grant_type=${encodeURIComponent('urn:ietf:params:oauth:grant-type:device_code')}` + `&client_id=${CLIENT_ID}` + `&device_code=${encodeURIComponent(deviceCode)}`;
38
+ const body = {
39
+ grant_type: 'urn:ietf:params:oauth:grant-type:device_code',
40
+ client_id: CLIENT_ID,
41
+ device_code: deviceCode
42
+ };
43
+ log(`Poll URL: POST ${TOKEN_URL}`);
44
+ log(`Request body:`, JSON.stringify(body, null, 2));
45
+ let attempt = 0;
23
46
  while (Date.now() < deadline) {
24
- const res = await fetch(url, {
25
- method: 'POST'
47
+ attempt++;
48
+ log(`Poll attempt #${attempt}`);
49
+ const res = await fetch(TOKEN_URL, {
50
+ method: 'POST',
51
+ headers: {
52
+ 'Content-Type': 'application/json'
53
+ },
54
+ body: JSON.stringify(body)
26
55
  });
56
+ log(`Response: ${res.status} ${res.statusText}`);
27
57
  if (res.ok) {
28
- return res.json();
58
+ const token = await res.json();
59
+ log(`Token response:`, JSON.stringify({
60
+ ...token,
61
+ access_token: '***',
62
+ refresh_token: '***'
63
+ }, null, 2));
64
+ return token;
29
65
  }
30
- const body = await res.json().catch(() => ({}));
31
- if (body.error === 'access_denied') {
66
+ const errorBody = await res.json().catch(() => ({}));
67
+ log(`Poll error body:`, JSON.stringify(errorBody, null, 2));
68
+ if (errorBody.error === 'access_denied') {
32
69
  throw new Error('Access denied');
33
70
  }
34
71
 
@@ -37,6 +74,51 @@ async function pollToken(deviceCode) {
37
74
  }
38
75
  throw new Error('Verification failed — timed out after 60 seconds. Please run `web5 login` again.');
39
76
  }
77
+ export async function promptForSiteId() {
78
+ return new Promise(resolve => {
79
+ const rl = readline.createInterface({
80
+ input: process.stdin,
81
+ output: process.stdout
82
+ });
83
+ rl.question(' Enter your site ID (msid) or press Enter to skip: ', answer => {
84
+ rl.close();
85
+ const trimmed = answer.trim();
86
+ const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
87
+ resolve(UUID_RE.test(trimmed) ? trimmed : null);
88
+ });
89
+ });
90
+ }
91
+ export async function refreshAccessToken(refreshToken, siteId) {
92
+ const body = {
93
+ grant_type: 'refresh_token',
94
+ client_id: CLIENT_ID,
95
+ refresh_token: refreshToken
96
+ };
97
+ if (siteId) {
98
+ body.site_id = siteId;
99
+ }
100
+ log(`Refreshing access token: POST ${TOKEN_URL}`);
101
+ const res = await fetch(TOKEN_URL, {
102
+ method: 'POST',
103
+ headers: {
104
+ 'Content-Type': 'application/json'
105
+ },
106
+ body: JSON.stringify(body)
107
+ });
108
+ log(`Refresh response: ${res.status} ${res.statusText}`);
109
+ if (!res.ok) {
110
+ const errorBody = await res.json().catch(() => ({}));
111
+ log(`Refresh error body:`, JSON.stringify(errorBody, null, 2));
112
+ throw new Error(`Token refresh failed (${res.status}): ${errorBody.error ?? res.statusText}`);
113
+ }
114
+ const token = await res.json();
115
+ log(`Refresh token response:`, JSON.stringify({
116
+ ...token,
117
+ access_token: '***',
118
+ refresh_token: '***'
119
+ }, null, 2));
120
+ return token;
121
+ }
40
122
  async function pressEnterToContinue() {
41
123
  return new Promise(resolve => {
42
124
  const rl = readline.createInterface({
@@ -49,16 +131,27 @@ async function pressEnterToContinue() {
49
131
  });
50
132
  });
51
133
  }
52
- export async function runDeviceFlow() {
134
+ export async function runDeviceFlow(verbose, noBrowser) {
135
+ if (verbose === void 0) {
136
+ verbose = false;
137
+ }
138
+ if (noBrowser === void 0) {
139
+ noBrowser = false;
140
+ }
141
+ verboseMode = verbose;
53
142
  const code = await requestDeviceCode();
54
143
  console.log('');
55
144
  info(`Verification code: ${code.userCode}`);
56
145
  console.log(` ${code.verificationUri}`);
57
146
  console.log('');
58
- await pressEnterToContinue();
59
- const open = (await import('open')).default;
60
- await open(code.verificationUri);
61
- console.log('');
147
+ if (noBrowser) {
148
+ info('Open the URL above in your browser to authenticate.');
149
+ } else {
150
+ await pressEnterToContinue();
151
+ const open = (await import('open')).default;
152
+ await open(code.verificationUri);
153
+ console.log('');
154
+ }
62
155
  const spin = spinner('Waiting for approval...');
63
156
  try {
64
157
  const token = await pollToken(code.deviceCode);
@@ -1 +1 @@
1
- {"version":3,"names":["readline","spinner","info","CLIENT_ID","DEVICE_CODE_URL","TOKEN_URL","POLL_INTERVAL_MS","POLL_TIMEOUT_MS","sleep","ms","Promise","resolve","setTimeout","requestDeviceCode","res","fetch","ok","Error","status","statusText","json","pollToken","deviceCode","deadline","Date","now","url","encodeURIComponent","method","body","catch","error","pressEnterToContinue","rl","createInterface","input","process","stdin","output","stdout","question","close","runDeviceFlow","code","console","log","userCode","verificationUri","open","default","spin","token","succeed","err","fail"],"sources":["../../../src/auth/deviceFlow.ts"],"sourcesContent":["import * as readline from 'readline';\nimport { spinner, info } from '../utils/print';\n\n// const CLIENT_ID = '602051c7-ec4b-4334-b90d-b029b076ba8f';\nconst CLIENT_ID = '6f95cec8-3e98-48b9-b4e5-1fb92fcd9973';\nconst DEVICE_CODE_URL = 'https://www.wixapis.com/oauth2/device/code';\nconst TOKEN_URL = 'https://www.wixapis.com/oauth2/token';\nconst POLL_INTERVAL_MS = 3000;\nconst POLL_TIMEOUT_MS = 60_000;\n\ninterface DeviceCodeResponse {\n deviceCode: string;\n userCode: string;\n verificationUri: string;\n expiresIn: number;\n}\n\nexport interface TokenResponse {\n access_token: string;\n token_type: string;\n expires_in: number;\n refresh_token: string;\n}\n\nasync function sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nasync function requestDeviceCode(): Promise<DeviceCodeResponse> {\n const res = await fetch(\n `${DEVICE_CODE_URL}?client_id=${CLIENT_ID}&scope=session_bound_access`,\n );\n if (!res.ok) {\n throw new Error(\n `Device code request failed: ${res.status} ${res.statusText}`,\n );\n }\n return res.json() as Promise<DeviceCodeResponse>;\n}\n\nasync function pollToken(deviceCode: string): Promise<TokenResponse> {\n const deadline = Date.now() + POLL_TIMEOUT_MS;\n const url =\n `${TOKEN_URL}` +\n `?grant_type=${encodeURIComponent(\n 'urn:ietf:params:oauth:grant-type:device_code',\n )}` +\n `&client_id=${CLIENT_ID}` +\n `&device_code=${encodeURIComponent(deviceCode)}`;\n\n while (Date.now() < deadline) {\n const res = await fetch(url, { method: 'POST' });\n\n if (res.ok) {\n return res.json() as Promise<TokenResponse>;\n }\n\n const body = (await res.json().catch(() => ({}))) as { error?: string };\n\n if (body.error === 'access_denied') {\n throw new Error('Access denied');\n }\n\n // authorization_pending, slow_down, unknown_error, or any transient error → keep polling\n await sleep(POLL_INTERVAL_MS);\n }\n\n throw new Error(\n 'Verification failed — timed out after 60 seconds. Please run `web5 login` again.',\n );\n}\n\nasync function pressEnterToContinue(): Promise<void> {\n return new Promise((resolve) => {\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n rl.question(' Press Enter to open in browser...', () => {\n rl.close();\n resolve();\n });\n });\n}\n\nexport async function runDeviceFlow(): Promise<TokenResponse> {\n const code = await requestDeviceCode();\n\n console.log('');\n info(`Verification code: ${code.userCode}`);\n console.log(` ${code.verificationUri}`);\n console.log('');\n\n await pressEnterToContinue();\n\n const open = (await import('open')).default;\n await open(code.verificationUri);\n console.log('');\n\n const spin = spinner('Waiting for approval...');\n\n try {\n const token = await pollToken(code.deviceCode);\n spin.succeed('Approved');\n return token;\n } catch (err) {\n spin.fail('Authentication failed');\n throw err;\n }\n}\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"names":["readline","spinner","info","CLIENT_ID","DEVICE_CODE_URL","TOKEN_URL","POLL_INTERVAL_MS","POLL_TIMEOUT_MS","verboseMode","log","_len","arguments","length","args","Array","_key","console","sleep","ms","Promise","resolve","setTimeout","requestDeviceCode","url","res","fetch","status","statusText","ok","body","text","catch","Error","data","json","JSON","stringify","pollToken","deviceCode","deadline","Date","now","grant_type","client_id","device_code","attempt","method","headers","token","access_token","refresh_token","errorBody","error","promptForSiteId","rl","createInterface","input","process","stdin","output","stdout","question","answer","close","trimmed","trim","UUID_RE","test","refreshAccessToken","refreshToken","siteId","site_id","pressEnterToContinue","runDeviceFlow","verbose","noBrowser","code","userCode","verificationUri","open","default","spin","succeed","err","fail"],"sources":["../../../src/auth/deviceFlow.ts"],"sourcesContent":["import * as readline from 'readline';\nimport { spinner, info } from '../utils/print';\n\n// const CLIENT_ID = '602051c7-ec4b-4334-b90d-b029b076ba8f';\nconst CLIENT_ID = '6f95cec8-3e98-48b9-b4e5-1fb92fcd9973';\nconst DEVICE_CODE_URL = 'https://www.wixapis.com/oauth2/device/code';\nconst TOKEN_URL = 'https://www.wixapis.com/oauth2/token';\nconst POLL_INTERVAL_MS = 3000;\nconst POLL_TIMEOUT_MS = 60_000;\n\nlet verboseMode = false;\n\nfunction log(...args: unknown[]): void {\n if (verboseMode) {\n console.log('[auth]', ...args);\n }\n}\n\ninterface DeviceCodeResponse {\n deviceCode: string;\n userCode: string;\n verificationUri: string;\n expiresIn: number;\n}\n\nexport interface TokenResponse {\n access_token: string;\n token_type: string;\n expires_in: number;\n refresh_token: string;\n}\n\nasync function sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nasync function requestDeviceCode(): Promise<DeviceCodeResponse> {\n const url = `${DEVICE_CODE_URL}?client_id=${CLIENT_ID}&scope=session_bound_access`;\n log(`POST ${url}`);\n\n const res = await fetch(url);\n log(`Response: ${res.status} ${res.statusText}`);\n\n if (!res.ok) {\n const body = await res.text().catch(() => '');\n log(`Error body: ${body}`);\n throw new Error(\n `Device code request failed: ${res.status} ${res.statusText}`,\n );\n }\n\n const data = (await res.json()) as DeviceCodeResponse;\n log(`Device code response:`, JSON.stringify(data, null, 2));\n return data;\n}\n\nasync function pollToken(deviceCode: string): Promise<TokenResponse> {\n const deadline = Date.now() + POLL_TIMEOUT_MS;\n const body = {\n grant_type: 'urn:ietf:params:oauth:grant-type:device_code',\n client_id: CLIENT_ID,\n device_code: deviceCode,\n };\n\n log(`Poll URL: POST ${TOKEN_URL}`);\n log(`Request body:`, JSON.stringify(body, null, 2));\n\n let attempt = 0;\n while (Date.now() < deadline) {\n attempt++;\n log(`Poll attempt #${attempt}`);\n const res = await fetch(TOKEN_URL, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(body),\n });\n log(`Response: ${res.status} ${res.statusText}`);\n\n if (res.ok) {\n const token = (await res.json()) as TokenResponse;\n log(\n `Token response:`,\n JSON.stringify(\n { ...token, access_token: '***', refresh_token: '***' },\n null,\n 2,\n ),\n );\n return token;\n }\n\n const errorBody = (await res.json().catch(() => ({}))) as {\n error?: string;\n };\n log(`Poll error body:`, JSON.stringify(errorBody, null, 2));\n\n if (errorBody.error === 'access_denied') {\n throw new Error('Access denied');\n }\n\n // authorization_pending, slow_down, unknown_error, or any transient error → keep polling\n await sleep(POLL_INTERVAL_MS);\n }\n\n throw new Error(\n 'Verification failed — timed out after 60 seconds. Please run `web5 login` again.',\n );\n}\n\nexport async function promptForSiteId(): Promise<string | null> {\n return new Promise((resolve) => {\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n rl.question(\n ' Enter your site ID (msid) or press Enter to skip: ',\n (answer) => {\n rl.close();\n const trimmed = answer.trim();\n const UUID_RE =\n /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\n resolve(UUID_RE.test(trimmed) ? trimmed : null);\n },\n );\n });\n}\n\nexport async function refreshAccessToken(\n refreshToken: string,\n siteId?: string,\n): Promise<TokenResponse> {\n const body: Record<string, string> = {\n grant_type: 'refresh_token',\n client_id: CLIENT_ID,\n refresh_token: refreshToken,\n };\n\n if (siteId) {\n body.site_id = siteId;\n }\n\n log(`Refreshing access token: POST ${TOKEN_URL}`);\n\n const res = await fetch(TOKEN_URL, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(body),\n });\n\n log(`Refresh response: ${res.status} ${res.statusText}`);\n\n if (!res.ok) {\n const errorBody = (await res.json().catch(() => ({}))) as {\n error?: string;\n };\n log(`Refresh error body:`, JSON.stringify(errorBody, null, 2));\n throw new Error(\n `Token refresh failed (${res.status}): ${\n errorBody.error ?? res.statusText\n }`,\n );\n }\n\n const token = (await res.json()) as TokenResponse;\n log(\n `Refresh token response:`,\n JSON.stringify(\n { ...token, access_token: '***', refresh_token: '***' },\n null,\n 2,\n ),\n );\n return token;\n}\n\nasync function pressEnterToContinue(): Promise<void> {\n return new Promise((resolve) => {\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n rl.question(' Press Enter to open in browser...', () => {\n rl.close();\n resolve();\n });\n });\n}\n\nexport async function runDeviceFlow(\n verbose = false,\n noBrowser = false,\n): Promise<TokenResponse> {\n verboseMode = verbose;\n const code = await requestDeviceCode();\n\n console.log('');\n info(`Verification code: ${code.userCode}`);\n console.log(` ${code.verificationUri}`);\n console.log('');\n\n if (noBrowser) {\n info('Open the URL above in your browser to authenticate.');\n } else {\n await pressEnterToContinue();\n const open = (await import('open')).default;\n await open(code.verificationUri);\n console.log('');\n }\n\n const spin = spinner('Waiting for approval...');\n\n try {\n const token = await pollToken(code.deviceCode);\n spin.succeed('Approved');\n return token;\n } catch (err) {\n spin.fail('Authentication failed');\n throw err;\n }\n}\n"],"mappings":"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","ignoreList":[]}
@@ -1,7 +1,25 @@
1
- import { runDeviceFlow } from './deviceFlow';
1
+ import { runDeviceFlow, refreshAccessToken, promptForSiteId } from './deviceFlow';
2
2
  import { writeCredentials, readCredentials, clearCredentials } from './secretStore';
3
3
  import { success } from '../utils/print';
4
- export async function login(apiKey) {
4
+ // Refresh proactively if the access token expires within this window
5
+ const EXPIRY_BUFFER_MS = 60_000;
6
+ function credentialsFromToken(token, siteId) {
7
+ return {
8
+ access_token: token.access_token,
9
+ refresh_token: token.refresh_token,
10
+ expires_at: Date.now() + token.expires_in * 1000,
11
+ ...(siteId ? {
12
+ site_id: siteId
13
+ } : {})
14
+ };
15
+ }
16
+ export async function login(apiKey, verbose, opts) {
17
+ if (verbose === void 0) {
18
+ verbose = false;
19
+ }
20
+ if (opts === void 0) {
21
+ opts = {};
22
+ }
5
23
  if (apiKey) {
6
24
  await writeCredentials({
7
25
  api_key: apiKey
@@ -9,13 +27,31 @@ export async function login(apiKey) {
9
27
  success('API key saved');
10
28
  return;
11
29
  }
12
- const token = await runDeviceFlow();
13
- await writeCredentials({
14
- access_token: token.access_token,
15
- refresh_token: token.refresh_token
16
- });
30
+ const token = await runDeviceFlow(verbose, opts.noBrowser ?? false);
31
+ console.log('');
32
+ const siteId = opts.siteId ?? (await promptForSiteId());
33
+ if (siteId) {
34
+ const siteToken = await refreshAccessToken(token.refresh_token, siteId);
35
+ await writeCredentials(credentialsFromToken(siteToken, siteId));
36
+ } else {
37
+ await writeCredentials(credentialsFromToken(token));
38
+ }
17
39
  success('Authenticated');
18
- success('Tokens stored in system keychain');
40
+ }
41
+ export async function switchSite(siteId) {
42
+ const creds = await readCredentials();
43
+ if (!creds) {
44
+ throw new Error('Not authenticated. Run `web5 login` first.');
45
+ }
46
+ if (creds.api_key) {
47
+ throw new Error('Cannot switch site when using an API key — re-run `web5 login --site-id <msid>` instead.');
48
+ }
49
+ if (!creds.refresh_token) {
50
+ throw new Error('No refresh token available. Run `web5 login` first.');
51
+ }
52
+ const refreshed = await refreshAccessToken(creds.refresh_token, siteId);
53
+ await writeCredentials(credentialsFromToken(refreshed, siteId));
54
+ success(`Switched to site ${siteId}`);
19
55
  }
20
56
  export async function logout() {
21
57
  await clearCredentials();
@@ -26,15 +62,37 @@ export async function getToken() {
26
62
  if (!creds) {
27
63
  return null;
28
64
  }
29
- if (creds.access_token) {
30
- return creds.access_token;
31
- }
65
+
66
+ // API key path — no expiry concept
32
67
  if (creds.api_key) {
33
68
  return creds.api_key;
34
69
  }
35
- return creds.refresh_token ?? null;
70
+
71
+ // Access token still valid
72
+ if (creds.access_token && creds.expires_at && creds.expires_at - Date.now() > EXPIRY_BUFFER_MS) {
73
+ return creds.access_token;
74
+ }
75
+
76
+ // Access token missing or expiring soon — try refresh
77
+ if (creds.refresh_token) {
78
+ try {
79
+ const refreshed = await refreshAccessToken(creds.refresh_token, creds.site_id);
80
+ const updated = credentialsFromToken(refreshed, creds.site_id);
81
+ await writeCredentials(updated);
82
+ return updated.access_token;
83
+ } catch {
84
+ // Refresh token is expired or revoked — force re-login
85
+ await clearCredentials();
86
+ throw new Error('Session expired. Run `web5 login` to re-authenticate.');
87
+ }
88
+ }
89
+ return null;
36
90
  }
37
91
  export async function isAuthenticated() {
38
- return (await getToken()) !== null;
92
+ try {
93
+ return (await getToken()) !== null;
94
+ } catch {
95
+ return false;
96
+ }
39
97
  }
40
98
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"names":["runDeviceFlow","writeCredentials","readCredentials","clearCredentials","success","login","apiKey","api_key","token","access_token","refresh_token","logout","getToken","creds","isAuthenticated"],"sources":["../../../src/auth/index.ts"],"sourcesContent":["import { runDeviceFlow } from './deviceFlow';\nimport {\n writeCredentials,\n readCredentials,\n clearCredentials,\n} from './secretStore';\nimport { success } from '../utils/print';\n\nexport type { Credentials } from './secretStore';\n\nexport async function login(apiKey?: string): Promise<void> {\n if (apiKey) {\n await writeCredentials({ api_key: apiKey });\n success('API key saved');\n return;\n }\n\n const token = await runDeviceFlow();\n await writeCredentials({\n access_token: token.access_token,\n refresh_token: token.refresh_token,\n });\n success('Authenticated');\n success('Tokens stored in system keychain');\n}\n\nexport async function logout(): Promise<void> {\n await clearCredentials();\n success('Signed out \\u2014 credentials removed');\n}\n\nexport async function getToken(): Promise<string | null> {\n const creds = await readCredentials();\n if (!creds) {\n return null;\n }\n if (creds.access_token) {\n return creds.access_token;\n }\n if (creds.api_key) {\n return creds.api_key;\n }\n return creds.refresh_token ?? null;\n}\n\nexport async function isAuthenticated(): Promise<boolean> {\n return (await getToken()) !== null;\n}\n"],"mappings":"AAAA,SAASA,aAAa,QAAQ,cAAc;AAC5C,SACEC,gBAAgB,EAChBC,eAAe,EACfC,gBAAgB,QACX,eAAe;AACtB,SAASC,OAAO,QAAQ,gBAAgB;AAIxC,OAAO,eAAeC,KAAKA,CAACC,MAAe,EAAiB;EAC1D,IAAIA,MAAM,EAAE;IACV,MAAML,gBAAgB,CAAC;MAAEM,OAAO,EAAED;IAAO,CAAC,CAAC;IAC3CF,OAAO,CAAC,eAAe,CAAC;IACxB;EACF;EAEA,MAAMI,KAAK,GAAG,MAAMR,aAAa,CAAC,CAAC;EACnC,MAAMC,gBAAgB,CAAC;IACrBQ,YAAY,EAAED,KAAK,CAACC,YAAY;IAChCC,aAAa,EAAEF,KAAK,CAACE;EACvB,CAAC,CAAC;EACFN,OAAO,CAAC,eAAe,CAAC;EACxBA,OAAO,CAAC,kCAAkC,CAAC;AAC7C;AAEA,OAAO,eAAeO,MAAMA,CAAA,EAAkB;EAC5C,MAAMR,gBAAgB,CAAC,CAAC;EACxBC,OAAO,CAAC,uCAAuC,CAAC;AAClD;AAEA,OAAO,eAAeQ,QAAQA,CAAA,EAA2B;EACvD,MAAMC,KAAK,GAAG,MAAMX,eAAe,CAAC,CAAC;EACrC,IAAI,CAACW,KAAK,EAAE;IACV,OAAO,IAAI;EACb;EACA,IAAIA,KAAK,CAACJ,YAAY,EAAE;IACtB,OAAOI,KAAK,CAACJ,YAAY;EAC3B;EACA,IAAII,KAAK,CAACN,OAAO,EAAE;IACjB,OAAOM,KAAK,CAACN,OAAO;EACtB;EACA,OAAOM,KAAK,CAACH,aAAa,IAAI,IAAI;AACpC;AAEA,OAAO,eAAeI,eAAeA,CAAA,EAAqB;EACxD,OAAO,CAAC,MAAMF,QAAQ,CAAC,CAAC,MAAM,IAAI;AACpC","ignoreList":[]}
1
+ {"version":3,"names":["runDeviceFlow","refreshAccessToken","promptForSiteId","writeCredentials","readCredentials","clearCredentials","success","EXPIRY_BUFFER_MS","credentialsFromToken","token","siteId","access_token","refresh_token","expires_at","Date","now","expires_in","site_id","login","apiKey","verbose","opts","api_key","noBrowser","console","log","siteToken","switchSite","creds","Error","refreshed","logout","getToken","updated","isAuthenticated"],"sources":["../../../src/auth/index.ts"],"sourcesContent":["import {\n runDeviceFlow,\n refreshAccessToken,\n promptForSiteId,\n} from './deviceFlow';\nimport {\n writeCredentials,\n readCredentials,\n clearCredentials,\n} from './secretStore';\nimport { success } from '../utils/print';\n\nexport type { Credentials } from './secretStore';\n\n// Refresh proactively if the access token expires within this window\nconst EXPIRY_BUFFER_MS = 60_000;\n\nfunction credentialsFromToken(\n token: {\n access_token: string;\n refresh_token: string;\n expires_in: number;\n },\n siteId?: string,\n) {\n return {\n access_token: token.access_token,\n refresh_token: token.refresh_token,\n expires_at: Date.now() + token.expires_in * 1000,\n ...(siteId ? { site_id: siteId } : {}),\n };\n}\n\nexport async function login(\n apiKey?: string,\n verbose = false,\n opts: { siteId?: string; noBrowser?: boolean } = {},\n): Promise<void> {\n if (apiKey) {\n await writeCredentials({ api_key: apiKey });\n success('API key saved');\n return;\n }\n\n const token = await runDeviceFlow(verbose, opts.noBrowser ?? false);\n\n console.log('');\n const siteId = opts.siteId ?? (await promptForSiteId());\n if (siteId) {\n const siteToken = await refreshAccessToken(token.refresh_token, siteId);\n await writeCredentials(credentialsFromToken(siteToken, siteId));\n } else {\n await writeCredentials(credentialsFromToken(token));\n }\n\n success('Authenticated');\n}\n\nexport async function switchSite(siteId: string): Promise<void> {\n const creds = await readCredentials();\n if (!creds) {\n throw new Error('Not authenticated. Run `web5 login` first.');\n }\n if (creds.api_key) {\n throw new Error('Cannot switch site when using an API key — re-run `web5 login --site-id <msid>` instead.');\n }\n if (!creds.refresh_token) {\n throw new Error('No refresh token available. Run `web5 login` first.');\n }\n const refreshed = await refreshAccessToken(creds.refresh_token, siteId);\n await writeCredentials(credentialsFromToken(refreshed, siteId));\n success(`Switched to site ${siteId}`);\n}\n\nexport async function logout(): Promise<void> {\n await clearCredentials();\n success('Signed out \\u2014 credentials removed');\n}\n\nexport async function getToken(): Promise<string | null> {\n const creds = await readCredentials();\n if (!creds) {\n return null;\n }\n\n // API key path — no expiry concept\n if (creds.api_key) {\n return creds.api_key;\n }\n\n // Access token still valid\n if (\n creds.access_token &&\n creds.expires_at &&\n creds.expires_at - Date.now() > EXPIRY_BUFFER_MS\n ) {\n return creds.access_token;\n }\n\n // Access token missing or expiring soon — try refresh\n if (creds.refresh_token) {\n try {\n const refreshed = await refreshAccessToken(\n creds.refresh_token,\n creds.site_id,\n );\n const updated = credentialsFromToken(refreshed, creds.site_id);\n await writeCredentials(updated);\n return updated.access_token;\n } catch {\n // Refresh token is expired or revoked — force re-login\n await clearCredentials();\n throw new Error('Session expired. Run `web5 login` to re-authenticate.');\n }\n }\n\n return null;\n}\n\nexport async function isAuthenticated(): Promise<boolean> {\n try {\n return (await getToken()) !== null;\n } catch {\n return false;\n }\n}\n"],"mappings":"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","ignoreList":[]}
@@ -1 +1 @@
1
- {"version":3,"names":["crypto","os","path","readFile","unlink","atomicWrite","SERVICE","ACCOUNT","CRED_FILE","join","homedir","_storeType","getDerivedKey","uid","String","userInfo","raw","hostname","createHash","update","digest","detectStore","keytar","setPassword","deletePassword","encrypt","plaintext","key","iv","randomBytes","cipher","createCipheriv","encrypted","Buffer","concat","final","tag","getAuthTag","toString","decrypt","ciphertext","buf","from","subarray","decipher","createDecipheriv","setAuthTag","writeCredentials","creds","store","payload","JSON","stringify","readCredentials","apiKey","process","env","WEB5_API_KEY","api_key","getPassword","parse","trim","clearCredentials"],"sources":["../../../src/auth/secretStore.ts"],"sourcesContent":["import * as crypto from 'crypto';\nimport * as os from 'os';\nimport * as path from 'path';\nimport { readFile, unlink } from 'fs/promises';\nimport { atomicWrite } from '../utils/fs';\n\nconst SERVICE = 'wix-web5-cli';\nconst ACCOUNT = 'credentials';\nconst CRED_FILE = path.join(os.homedir(), '.wix', 'credentials.enc');\n\nexport interface Credentials {\n access_token?: string;\n refresh_token?: string;\n api_key?: string;\n}\n\ntype StoreType = 'keychain' | 'file';\n\nlet _storeType: StoreType | null = null;\n\nfunction getDerivedKey(): Buffer {\n const uid = String(os.userInfo().uid);\n const raw = `${os.hostname()}:${uid}`;\n return crypto.createHash('sha256').update(raw).digest();\n}\n\nasync function detectStore(): Promise<StoreType> {\n if (_storeType) {\n return _storeType;\n }\n\n try {\n // Dynamic import — keytar is optional; throws if the native module is absent\n const keytar = await import('keytar');\n await keytar.setPassword(SERVICE, '_probe', 'test');\n await keytar.deletePassword(SERVICE, '_probe');\n _storeType = 'keychain';\n } catch {\n _storeType = 'file';\n }\n\n return _storeType;\n}\n\nfunction encrypt(plaintext: string): string {\n const key = getDerivedKey();\n const iv = crypto.randomBytes(12);\n const cipher = crypto.createCipheriv('aes-256-gcm', key, iv);\n const encrypted = Buffer.concat([\n cipher.update(plaintext, 'utf8'),\n cipher.final(),\n ]);\n const tag = cipher.getAuthTag();\n return Buffer.concat([iv, tag, encrypted]).toString('base64');\n}\n\nfunction decrypt(ciphertext: string): string {\n const key = getDerivedKey();\n const buf = Buffer.from(ciphertext, 'base64');\n const iv = buf.subarray(0, 12);\n const tag = buf.subarray(12, 28);\n const encrypted = buf.subarray(28);\n const decipher = crypto.createDecipheriv('aes-256-gcm', key, iv);\n decipher.setAuthTag(tag);\n return decipher.update(encrypted) + decipher.final('utf8');\n}\n\nexport async function writeCredentials(creds: Credentials): Promise<void> {\n const store = await detectStore();\n const payload = JSON.stringify(creds);\n\n if (store === 'keychain') {\n const keytar = await import('keytar');\n await keytar.setPassword(SERVICE, ACCOUNT, payload);\n } else {\n await atomicWrite(CRED_FILE, encrypt(payload), 0o600);\n }\n}\n\nexport async function readCredentials(): Promise<Credentials | null> {\n // Env var takes highest priority — used in CI/CD pipelines\n const apiKey = process.env.WEB5_API_KEY;\n if (apiKey) {\n return { api_key: apiKey };\n }\n\n const store = await detectStore();\n\n if (store === 'keychain') {\n const keytar = await import('keytar');\n const payload = await keytar.getPassword(SERVICE, ACCOUNT);\n if (!payload) {\n return null;\n }\n return JSON.parse(payload) as Credentials;\n } else {\n try {\n const encrypted = await readFile(CRED_FILE, 'utf8');\n return JSON.parse(decrypt(encrypted.trim())) as Credentials;\n } catch {\n return null;\n }\n }\n}\n\nexport async function clearCredentials(): Promise<void> {\n const store = await detectStore();\n\n if (store === 'keychain') {\n const keytar = await import('keytar');\n await keytar.deletePassword(SERVICE, ACCOUNT);\n } else {\n try {\n await unlink(CRED_FILE);\n } catch {\n // Already gone — that's fine\n }\n }\n}\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"names":["crypto","os","path","readFile","unlink","atomicWrite","SERVICE","ACCOUNT","CRED_FILE","join","homedir","_storeType","getDerivedKey","uid","String","userInfo","raw","hostname","createHash","update","digest","detectStore","keytar","setPassword","deletePassword","encrypt","plaintext","key","iv","randomBytes","cipher","createCipheriv","encrypted","Buffer","concat","final","tag","getAuthTag","toString","decrypt","ciphertext","buf","from","subarray","decipher","createDecipheriv","setAuthTag","writeCredentials","creds","store","payload","JSON","stringify","readCredentials","apiKey","process","env","WEB5_API_KEY","api_key","getPassword","parse","trim","clearCredentials"],"sources":["../../../src/auth/secretStore.ts"],"sourcesContent":["import * as crypto from 'crypto';\nimport * as os from 'os';\nimport * as path from 'path';\nimport { readFile, unlink } from 'fs/promises';\nimport { atomicWrite } from '../utils/fs';\n\nconst SERVICE = 'wix-web5-cli';\nconst ACCOUNT = 'credentials';\nconst CRED_FILE = path.join(os.homedir(), '.wix', 'credentials.enc');\n\nexport interface Credentials {\n access_token?: string;\n refresh_token?: string;\n expires_at?: number; // unix ms — when access_token expires\n site_id?: string; // msid — when set, access_token is scoped to this site\n api_key?: string;\n}\n\ntype StoreType = 'keychain' | 'file';\n\nlet _storeType: StoreType | null = null;\n\nfunction getDerivedKey(): Buffer {\n const uid = String(os.userInfo().uid);\n const raw = `${os.hostname()}:${uid}`;\n return crypto.createHash('sha256').update(raw).digest();\n}\n\nasync function detectStore(): Promise<StoreType> {\n if (_storeType) {\n return _storeType;\n }\n\n try {\n // Dynamic import — keytar is optional; throws if the native module is absent\n const keytar = await import('keytar');\n await keytar.setPassword(SERVICE, '_probe', 'test');\n await keytar.deletePassword(SERVICE, '_probe');\n _storeType = 'keychain';\n } catch {\n _storeType = 'file';\n }\n\n return _storeType;\n}\n\nfunction encrypt(plaintext: string): string {\n const key = getDerivedKey();\n const iv = crypto.randomBytes(12);\n const cipher = crypto.createCipheriv('aes-256-gcm', key, iv);\n const encrypted = Buffer.concat([\n cipher.update(plaintext, 'utf8'),\n cipher.final(),\n ]);\n const tag = cipher.getAuthTag();\n return Buffer.concat([iv, tag, encrypted]).toString('base64');\n}\n\nfunction decrypt(ciphertext: string): string {\n const key = getDerivedKey();\n const buf = Buffer.from(ciphertext, 'base64');\n const iv = buf.subarray(0, 12);\n const tag = buf.subarray(12, 28);\n const encrypted = buf.subarray(28);\n const decipher = crypto.createDecipheriv('aes-256-gcm', key, iv);\n decipher.setAuthTag(tag);\n return decipher.update(encrypted) + decipher.final('utf8');\n}\n\nexport async function writeCredentials(creds: Credentials): Promise<void> {\n const store = await detectStore();\n const payload = JSON.stringify(creds);\n\n if (store === 'keychain') {\n const keytar = await import('keytar');\n await keytar.setPassword(SERVICE, ACCOUNT, payload);\n } else {\n await atomicWrite(CRED_FILE, encrypt(payload), 0o600);\n }\n}\n\nexport async function readCredentials(): Promise<Credentials | null> {\n // Env var takes highest priority — used in CI/CD pipelines\n const apiKey = process.env.WEB5_API_KEY;\n if (apiKey) {\n return { api_key: apiKey };\n }\n\n const store = await detectStore();\n\n if (store === 'keychain') {\n const keytar = await import('keytar');\n const payload = await keytar.getPassword(SERVICE, ACCOUNT);\n if (!payload) {\n return null;\n }\n return JSON.parse(payload) as Credentials;\n } else {\n try {\n const encrypted = await readFile(CRED_FILE, 'utf8');\n return JSON.parse(decrypt(encrypted.trim())) as Credentials;\n } catch {\n return null;\n }\n }\n}\n\nexport async function clearCredentials(): Promise<void> {\n const store = await detectStore();\n\n if (store === 'keychain') {\n const keytar = await import('keytar');\n await keytar.deletePassword(SERVICE, ACCOUNT);\n } else {\n try {\n await unlink(CRED_FILE);\n } catch {\n // Already gone — that's fine\n }\n }\n}\n"],"mappings":"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","ignoreList":[]}
package/dist/esm/cli.js CHANGED
@@ -2,15 +2,43 @@ import { Command } from 'commander';
2
2
  import * as fs from 'fs';
3
3
  import * as path from 'path';
4
4
  import { loginCommand } from './commands/login';
5
+ import { logoutCommand } from './commands/logout';
5
6
  import { initCommand } from './commands/init';
6
7
  import { validateCommand } from './commands/validate';
8
+ import { serveCommand } from './commands/serve';
9
+ import { embedCommand } from './commands/embed';
10
+ import { conversationsCommand } from './commands/conversationWizard';
11
+ import { instructionsCommand } from './commands/instructions';
12
+ import { deployCommand } from './commands/deploy';
13
+ import { getClientIdCommand } from './commands/getClientId';
14
+ import { whoamiCommand } from './commands/whoami';
7
15
 
8
16
  // Read version from package.json at runtime (works from dist/cjs/ via ../../)
9
17
  const pkg = JSON.parse(fs.readFileSync(path.join(__dirname, '../../package.json'), 'utf8'));
10
18
  const program = new Command();
11
- program.name('web5').description('Developer CLI for the Web5 platform').version(pkg.version);
19
+ program.name('web5').description('Developer CLI for the Web5 platform').version(pkg.version).option('--json', 'Output as machine-readable JSON (suppresses decorations)');
20
+
21
+ // Propagate --json to child processes via environment variable so that
22
+ // every command's action can call isJsonMode() without reading parent opts.
23
+ program.hook('preAction', () => {
24
+ if (program.opts().json) {
25
+ process.env.WEB5_JSON_MODE = '1';
26
+ }
27
+ });
28
+
29
+ // ── Commands ──────────────────────────────────────────────────────────────
12
30
  program.addCommand(loginCommand);
31
+ program.addCommand(logoutCommand);
32
+ program.addCommand(whoamiCommand);
13
33
  program.addCommand(initCommand);
14
34
  program.addCommand(validateCommand);
35
+ program.addCommand(deployCommand);
36
+ program.addCommand(serveCommand);
37
+ program.addCommand(embedCommand);
38
+ program.addCommand(getClientIdCommand);
39
+
40
+ // ── Wizards ───────────────────────────────────────────────────────────────
41
+ program.addCommand(instructionsCommand);
42
+ program.addCommand(conversationsCommand);
15
43
  program.parseAsync(process.argv);
16
44
  //# sourceMappingURL=cli.js.map
@@ -1 +1 @@
1
- {"version":3,"names":["Command","fs","path","loginCommand","initCommand","validateCommand","pkg","JSON","parse","readFileSync","join","__dirname","program","name","description","version","addCommand","parseAsync","process","argv"],"sources":["../../src/cli.ts"],"sourcesContent":["import { Command } from 'commander';\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport { loginCommand } from './commands/login';\nimport { initCommand } from './commands/init';\nimport { validateCommand } from './commands/validate';\n\n// Read version from package.json at runtime (works from dist/cjs/ via ../../)\nconst pkg = JSON.parse(\n fs.readFileSync(path.join(__dirname, '../../package.json'), 'utf8'),\n) as { version: string };\n\nconst program = new Command();\n\nprogram\n .name('web5')\n .description('Developer CLI for the Web5 platform')\n .version(pkg.version);\n\nprogram.addCommand(loginCommand);\nprogram.addCommand(initCommand);\nprogram.addCommand(validateCommand);\n\nprogram.parseAsync(process.argv);\n"],"mappings":"AAAA,SAASA,OAAO,QAAQ,WAAW;AACnC,OAAO,KAAKC,EAAE,MAAM,IAAI;AACxB,OAAO,KAAKC,IAAI,MAAM,MAAM;AAC5B,SAASC,YAAY,QAAQ,kBAAkB;AAC/C,SAASC,WAAW,QAAQ,iBAAiB;AAC7C,SAASC,eAAe,QAAQ,qBAAqB;;AAErD;AACA,MAAMC,GAAG,GAAGC,IAAI,CAACC,KAAK,CACpBP,EAAE,CAACQ,YAAY,CAACP,IAAI,CAACQ,IAAI,CAACC,SAAS,EAAE,oBAAoB,CAAC,EAAE,MAAM,CACpE,CAAwB;AAExB,MAAMC,OAAO,GAAG,IAAIZ,OAAO,CAAC,CAAC;AAE7BY,OAAO,CACJC,IAAI,CAAC,MAAM,CAAC,CACZC,WAAW,CAAC,qCAAqC,CAAC,CAClDC,OAAO,CAACT,GAAG,CAACS,OAAO,CAAC;AAEvBH,OAAO,CAACI,UAAU,CAACb,YAAY,CAAC;AAChCS,OAAO,CAACI,UAAU,CAACZ,WAAW,CAAC;AAC/BQ,OAAO,CAACI,UAAU,CAACX,eAAe,CAAC;AAEnCO,OAAO,CAACK,UAAU,CAACC,OAAO,CAACC,IAAI,CAAC","ignoreList":[]}
1
+ {"version":3,"names":["Command","fs","path","loginCommand","logoutCommand","initCommand","validateCommand","serveCommand","embedCommand","conversationsCommand","instructionsCommand","deployCommand","getClientIdCommand","whoamiCommand","pkg","JSON","parse","readFileSync","join","__dirname","program","name","description","version","option","hook","opts","json","process","env","WEB5_JSON_MODE","addCommand","parseAsync","argv"],"sources":["../../src/cli.ts"],"sourcesContent":["import { Command } from 'commander';\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport { loginCommand } from './commands/login';\nimport { logoutCommand } from './commands/logout';\nimport { initCommand } from './commands/init';\nimport { validateCommand } from './commands/validate';\nimport { serveCommand } from './commands/serve';\nimport { embedCommand } from './commands/embed';\nimport { conversationsCommand } from './commands/conversationWizard';\nimport { instructionsCommand } from './commands/instructions';\nimport { deployCommand } from './commands/deploy';\nimport { getClientIdCommand } from './commands/getClientId';\nimport { whoamiCommand } from './commands/whoami';\n\n// Read version from package.json at runtime (works from dist/cjs/ via ../../)\nconst pkg = JSON.parse(\n fs.readFileSync(path.join(__dirname, '../../package.json'), 'utf8'),\n) as { version: string };\n\nconst program = new Command();\n\nprogram\n .name('web5')\n .description('Developer CLI for the Web5 platform')\n .version(pkg.version)\n .option('--json', 'Output as machine-readable JSON (suppresses decorations)');\n\n// Propagate --json to child processes via environment variable so that\n// every command's action can call isJsonMode() without reading parent opts.\nprogram.hook('preAction', () => {\n if (program.opts().json) {\n process.env.WEB5_JSON_MODE = '1';\n }\n});\n\n// ── Commands ──────────────────────────────────────────────────────────────\nprogram.addCommand(loginCommand);\nprogram.addCommand(logoutCommand);\nprogram.addCommand(whoamiCommand);\nprogram.addCommand(initCommand);\nprogram.addCommand(validateCommand);\nprogram.addCommand(deployCommand);\nprogram.addCommand(serveCommand);\nprogram.addCommand(embedCommand);\nprogram.addCommand(getClientIdCommand);\n\n// ── Wizards ───────────────────────────────────────────────────────────────\nprogram.addCommand(instructionsCommand);\nprogram.addCommand(conversationsCommand);\n\nprogram.parseAsync(process.argv);\n"],"mappings":"AAAA,SAASA,OAAO,QAAQ,WAAW;AACnC,OAAO,KAAKC,EAAE,MAAM,IAAI;AACxB,OAAO,KAAKC,IAAI,MAAM,MAAM;AAC5B,SAASC,YAAY,QAAQ,kBAAkB;AAC/C,SAASC,aAAa,QAAQ,mBAAmB;AACjD,SAASC,WAAW,QAAQ,iBAAiB;AAC7C,SAASC,eAAe,QAAQ,qBAAqB;AACrD,SAASC,YAAY,QAAQ,kBAAkB;AAC/C,SAASC,YAAY,QAAQ,kBAAkB;AAC/C,SAASC,oBAAoB,QAAQ,+BAA+B;AACpE,SAASC,mBAAmB,QAAQ,yBAAyB;AAC7D,SAASC,aAAa,QAAQ,mBAAmB;AACjD,SAASC,kBAAkB,QAAQ,wBAAwB;AAC3D,SAASC,aAAa,QAAQ,mBAAmB;;AAEjD;AACA,MAAMC,GAAG,GAAGC,IAAI,CAACC,KAAK,CACpBf,EAAE,CAACgB,YAAY,CAACf,IAAI,CAACgB,IAAI,CAACC,SAAS,EAAE,oBAAoB,CAAC,EAAE,MAAM,CACpE,CAAwB;AAExB,MAAMC,OAAO,GAAG,IAAIpB,OAAO,CAAC,CAAC;AAE7BoB,OAAO,CACJC,IAAI,CAAC,MAAM,CAAC,CACZC,WAAW,CAAC,qCAAqC,CAAC,CAClDC,OAAO,CAACT,GAAG,CAACS,OAAO,CAAC,CACpBC,MAAM,CAAC,QAAQ,EAAE,0DAA0D,CAAC;;AAE/E;AACA;AACAJ,OAAO,CAACK,IAAI,CAAC,WAAW,EAAE,MAAM;EAC9B,IAAIL,OAAO,CAACM,IAAI,CAAC,CAAC,CAACC,IAAI,EAAE;IACvBC,OAAO,CAACC,GAAG,CAACC,cAAc,GAAG,GAAG;EAClC;AACF,CAAC,CAAC;;AAEF;AACAV,OAAO,CAACW,UAAU,CAAC5B,YAAY,CAAC;AAChCiB,OAAO,CAACW,UAAU,CAAC3B,aAAa,CAAC;AACjCgB,OAAO,CAACW,UAAU,CAAClB,aAAa,CAAC;AACjCO,OAAO,CAACW,UAAU,CAAC1B,WAAW,CAAC;AAC/Be,OAAO,CAACW,UAAU,CAACzB,eAAe,CAAC;AACnCc,OAAO,CAACW,UAAU,CAACpB,aAAa,CAAC;AACjCS,OAAO,CAACW,UAAU,CAACxB,YAAY,CAAC;AAChCa,OAAO,CAACW,UAAU,CAACvB,YAAY,CAAC;AAChCY,OAAO,CAACW,UAAU,CAACnB,kBAAkB,CAAC;;AAEtC;AACAQ,OAAO,CAACW,UAAU,CAACrB,mBAAmB,CAAC;AACvCU,OAAO,CAACW,UAAU,CAACtB,oBAAoB,CAAC;AAExCW,OAAO,CAACY,UAAU,CAACJ,OAAO,CAACK,IAAI,CAAC","ignoreList":[]}