@ms-cloudpack/cli 0.72.55 → 0.72.57

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 (61) hide show
  1. package/lib/commands/bundle/execute.js +7 -10
  2. package/lib/commands/bundle/execute.js.map +1 -1
  3. package/lib/commands/init/evaluatePath.js +10 -13
  4. package/lib/commands/init/evaluatePath.js.map +1 -1
  5. package/lib/commands/init/optimizeDependencies.d.ts +1 -2
  6. package/lib/commands/init/optimizeDependencies.d.ts.map +1 -1
  7. package/lib/commands/init/optimizeDependencies.js.map +1 -1
  8. package/lib/commands/init/verifyExports.d.ts +1 -2
  9. package/lib/commands/init/verifyExports.d.ts.map +1 -1
  10. package/lib/commands/init/verifyExports.js.map +1 -1
  11. package/lib/commands/link/formatLinkSummary.d.ts +1 -2
  12. package/lib/commands/link/formatLinkSummary.d.ts.map +1 -1
  13. package/lib/commands/link/formatLinkSummary.js.map +1 -1
  14. package/lib/commands/link/getActiveSessions.d.ts +1 -1
  15. package/lib/commands/link/getActiveSessions.d.ts.map +1 -1
  16. package/lib/commands/link/getActiveSessions.js.map +1 -1
  17. package/lib/commands/link/getSessionToLink.d.ts +1 -1
  18. package/lib/commands/link/getSessionToLink.d.ts.map +1 -1
  19. package/lib/commands/link/getSessionToLink.js.map +1 -1
  20. package/lib/commands/start/execute.d.ts.map +1 -1
  21. package/lib/commands/start/execute.js +2 -5
  22. package/lib/commands/start/execute.js.map +1 -1
  23. package/lib/commands/start/openBrowser.d.ts +4 -7
  24. package/lib/commands/start/openBrowser.d.ts.map +1 -1
  25. package/lib/commands/start/openBrowser.js +6 -3
  26. package/lib/commands/start/openBrowser.js.map +1 -1
  27. package/lib/commands/start/trackSession.d.ts +1 -1
  28. package/lib/commands/start/trackSession.d.ts.map +1 -1
  29. package/lib/commands/start/trackSession.js.map +1 -1
  30. package/lib/commands/sync/execute.d.ts.map +1 -1
  31. package/lib/commands/sync/execute.js +6 -10
  32. package/lib/commands/sync/execute.js.map +1 -1
  33. package/lib/types/AppPathDiscoveryMode.d.ts +2 -1
  34. package/lib/types/AppPathDiscoveryMode.d.ts.map +1 -1
  35. package/lib/types/AppPathDiscoveryMode.js.map +1 -1
  36. package/lib/utilities/CommandExecutor.d.ts.map +1 -1
  37. package/lib/utilities/CommandExecutor.js +18 -6
  38. package/lib/utilities/CommandExecutor.js.map +1 -1
  39. package/lib/utilities/{discoverAppPaths.d.ts → discoverLocalAppPaths.d.ts} +4 -4
  40. package/lib/utilities/discoverLocalAppPaths.d.ts.map +1 -0
  41. package/lib/utilities/{discoverAppPaths.js → discoverLocalAppPaths.js} +3 -3
  42. package/lib/utilities/discoverLocalAppPaths.js.map +1 -0
  43. package/lib/utilities/discoverRemoteAppPaths.d.ts +17 -0
  44. package/lib/utilities/discoverRemoteAppPaths.d.ts.map +1 -0
  45. package/lib/utilities/discoverRemoteAppPaths.js +53 -0
  46. package/lib/utilities/discoverRemoteAppPaths.js.map +1 -0
  47. package/lib/utilities/getDefaultLogin.d.ts +3 -0
  48. package/lib/utilities/getDefaultLogin.d.ts.map +1 -0
  49. package/lib/utilities/getDefaultLogin.js +5 -0
  50. package/lib/utilities/getDefaultLogin.js.map +1 -0
  51. package/lib/utilities/reusedOptions.d.ts +1 -0
  52. package/lib/utilities/reusedOptions.d.ts.map +1 -1
  53. package/lib/utilities/reusedOptions.js +1 -1
  54. package/lib/utilities/reusedOptions.js.map +1 -1
  55. package/lib/utilities/selectItemFromPaginatedResults.d.ts +20 -0
  56. package/lib/utilities/selectItemFromPaginatedResults.d.ts.map +1 -0
  57. package/lib/utilities/selectItemFromPaginatedResults.js +60 -0
  58. package/lib/utilities/selectItemFromPaginatedResults.js.map +1 -0
  59. package/package.json +5 -5
  60. package/lib/utilities/discoverAppPaths.d.ts.map +0 -1
  61. package/lib/utilities/discoverAppPaths.js.map +0 -1
@@ -0,0 +1,60 @@
1
+ import prompts from 'prompts';
2
+ const loadMoreValue = 'load_more';
3
+ const moveUpCursor = '\x1b[1A';
4
+ /**
5
+ * Presents an interactive prompt that lists accumulated items plus a "Load More" option.
6
+ * When "Load More" is selected, it fetches the next page and updates the list.
7
+ *
8
+ * @returns The entity selected by the user or null if nothing is chosen.
9
+ */
10
+ export async function selectItemFromPaginatedResults(params) {
11
+ const { message, getPage, getTitle, defaultPageSize = 10 } = params;
12
+ let continuationToken = undefined;
13
+ let accumulatedItems = [];
14
+ let response;
15
+ // Do-while loop to continue fetching pages until user selects an item or no more pages are available
16
+ do {
17
+ const previousLength = accumulatedItems.length;
18
+ // If no items have been loaded yet or if more pages exist, load the next page
19
+ if (accumulatedItems.length === 0 || continuationToken) {
20
+ const page = await getPage({ continuationToken, maxPageSize: defaultPageSize });
21
+ accumulatedItems = accumulatedItems.concat(page.items);
22
+ continuationToken = page.continuationToken;
23
+ }
24
+ const choices = accumulatedItems.map((item, index) => ({
25
+ title: getTitle(item),
26
+ value: index.toString(),
27
+ }));
28
+ // If more pages exist, add a "Load More" option at the end
29
+ if (continuationToken) {
30
+ choices.push({
31
+ title: 'Load More',
32
+ value: loadMoreValue,
33
+ });
34
+ }
35
+ // Display the selectable list
36
+ response = await prompts({
37
+ type: 'select',
38
+ name: 'selected',
39
+ message: continuationToken ? `${message} (or choose "Load More" to fetch more results)` : message,
40
+ choices,
41
+ initial: previousLength,
42
+ });
43
+ // Check if the user selected "Load More" or a valid item
44
+ if (response.selected === loadMoreValue) {
45
+ // Move the cursor up to overwrite the prompt with the new list
46
+ process.stdout.write(moveUpCursor);
47
+ }
48
+ else if (response.selected) {
49
+ // Return the chosen entity
50
+ return accumulatedItems[parseInt(response.selected)];
51
+ }
52
+ else {
53
+ // In case of no selection, return null
54
+ return null;
55
+ }
56
+ } while (continuationToken && response.selected === loadMoreValue);
57
+ // Return null if no valid selection was made
58
+ return null;
59
+ }
60
+ //# sourceMappingURL=selectItemFromPaginatedResults.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"selectItemFromPaginatedResults.js","sourceRoot":"","sources":["../../src/utilities/selectItemFromPaginatedResults.ts"],"names":[],"mappings":"AACA,OAAO,OAAO,MAAM,SAAS,CAAC;AAE9B,MAAM,aAAa,GAAG,WAAW,CAAC;AAClC,MAAM,YAAY,GAAG,SAAS,CAAC;AAgB/B;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,8BAA8B,CAClD,MAAgD;IAEhD,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,eAAe,GAAG,EAAE,EAAE,GAAG,MAAM,CAAC;IACpE,IAAI,iBAAiB,GAAuB,SAAS,CAAC;IACtD,IAAI,gBAAgB,GAAQ,EAAE,CAAC;IAC/B,IAAI,QAA8B,CAAC;IAEnC,qGAAqG;IACrG,GAAG,CAAC;QACF,MAAM,cAAc,GAAG,gBAAgB,CAAC,MAAM,CAAC;QAE/C,8EAA8E;QAC9E,IAAI,gBAAgB,CAAC,MAAM,KAAK,CAAC,IAAI,iBAAiB,EAAE,CAAC;YACvD,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,EAAE,iBAAiB,EAAE,WAAW,EAAE,eAAe,EAAE,CAAC,CAAC;YAChF,gBAAgB,GAAG,gBAAgB,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACvD,iBAAiB,GAAG,IAAI,CAAC,iBAAiB,CAAC;QAC7C,CAAC;QAED,MAAM,OAAO,GAAG,gBAAgB,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC;YACrD,KAAK,EAAE,QAAQ,CAAC,IAAI,CAAC;YACrB,KAAK,EAAE,KAAK,CAAC,QAAQ,EAAE;SACxB,CAAC,CAAC,CAAC;QAEJ,2DAA2D;QAC3D,IAAI,iBAAiB,EAAE,CAAC;YACtB,OAAO,CAAC,IAAI,CAAC;gBACX,KAAK,EAAE,WAAW;gBAClB,KAAK,EAAE,aAAa;aACrB,CAAC,CAAC;QACL,CAAC;QAED,8BAA8B;QAC9B,QAAQ,GAAG,MAAM,OAAO,CAAC;YACvB,IAAI,EAAE,QAAQ;YACd,IAAI,EAAE,UAAU;YAChB,OAAO,EAAE,iBAAiB,CAAC,CAAC,CAAC,GAAG,OAAO,gDAAgD,CAAC,CAAC,CAAC,OAAO;YACjG,OAAO;YACP,OAAO,EAAE,cAAc;SACxB,CAAC,CAAC;QAEH,yDAAyD;QACzD,IAAI,QAAQ,CAAC,QAAQ,KAAK,aAAa,EAAE,CAAC;YACxC,+DAA+D;YAC/D,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;QACrC,CAAC;aAAM,IAAI,QAAQ,CAAC,QAAQ,EAAE,CAAC;YAC7B,2BAA2B;YAC3B,OAAO,gBAAgB,CAAC,QAAQ,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC;QACvD,CAAC;aAAM,CAAC;YACN,uCAAuC;YACvC,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC,QAAQ,iBAAiB,IAAI,QAAQ,CAAC,QAAQ,KAAK,aAAa,EAAE;IAEnE,6CAA6C;IAC7C,OAAO,IAAI,CAAC;AACd,CAAC","sourcesContent":["import type { PageSettings, PagedResult } from '@ms-cloudpack/remote-cache';\nimport prompts from 'prompts';\n\nconst loadMoreValue = 'load_more';\nconst moveUpCursor = '\\x1b[1A';\n\ninterface SelectItemsFromPaginatedResultsParams<T> {\n /** The message to display to the user when selecting an item. */\n message: string;\n\n /** A function that fetches a page of items. */\n getPage: (pageSettings: PageSettings) => Promise<PagedResult<T>>;\n\n /** A function that returns a string to display for each item in the list. */\n getTitle: (item: T) => string;\n\n /** The default page size to use when fetching items. @default 10. */\n defaultPageSize?: number;\n}\n\n/**\n * Presents an interactive prompt that lists accumulated items plus a \"Load More\" option.\n * When \"Load More\" is selected, it fetches the next page and updates the list.\n *\n * @returns The entity selected by the user or null if nothing is chosen.\n */\nexport async function selectItemFromPaginatedResults<T>(\n params: SelectItemsFromPaginatedResultsParams<T>,\n): Promise<T | null> {\n const { message, getPage, getTitle, defaultPageSize = 10 } = params;\n let continuationToken: string | undefined = undefined;\n let accumulatedItems: T[] = [];\n let response: { selected: string };\n\n // Do-while loop to continue fetching pages until user selects an item or no more pages are available\n do {\n const previousLength = accumulatedItems.length;\n\n // If no items have been loaded yet or if more pages exist, load the next page\n if (accumulatedItems.length === 0 || continuationToken) {\n const page = await getPage({ continuationToken, maxPageSize: defaultPageSize });\n accumulatedItems = accumulatedItems.concat(page.items);\n continuationToken = page.continuationToken;\n }\n\n const choices = accumulatedItems.map((item, index) => ({\n title: getTitle(item),\n value: index.toString(),\n }));\n\n // If more pages exist, add a \"Load More\" option at the end\n if (continuationToken) {\n choices.push({\n title: 'Load More',\n value: loadMoreValue,\n });\n }\n\n // Display the selectable list\n response = await prompts({\n type: 'select',\n name: 'selected',\n message: continuationToken ? `${message} (or choose \"Load More\" to fetch more results)` : message,\n choices,\n initial: previousLength,\n });\n\n // Check if the user selected \"Load More\" or a valid item\n if (response.selected === loadMoreValue) {\n // Move the cursor up to overwrite the prompt with the new list\n process.stdout.write(moveUpCursor);\n } else if (response.selected) {\n // Return the chosen entity\n return accumulatedItems[parseInt(response.selected)];\n } else {\n // In case of no selection, return null\n return null;\n }\n } while (continuationToken && response.selected === loadMoreValue);\n\n // Return null if no valid selection was made\n return null;\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ms-cloudpack/cli",
3
- "version": "0.72.55",
3
+ "version": "0.72.57",
4
4
  "description": "The Cloudpack command line interface - a tool for managing fast inner and outer looping in web apps.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -10,18 +10,18 @@
10
10
  "cloudpack": "./bin/cloudpack.js"
11
11
  },
12
12
  "dependencies": {
13
- "@ms-cloudpack/api-server": "^0.60.1",
14
- "@ms-cloudpack/app-server": "^0.17.50",
13
+ "@ms-cloudpack/api-server": "^0.61.0",
14
+ "@ms-cloudpack/app-server": "^0.17.52",
15
15
  "@ms-cloudpack/bundler": "^0.24.0",
16
16
  "@ms-cloudpack/common-types": "^0.24.7",
17
17
  "@ms-cloudpack/config": "^0.33.16",
18
18
  "@ms-cloudpack/environment": "^0.1.1",
19
19
  "@ms-cloudpack/json-utilities": "^0.1.10",
20
- "@ms-cloudpack/overlay": "^0.17.131",
20
+ "@ms-cloudpack/overlay": "^0.17.133",
21
21
  "@ms-cloudpack/package-utilities": "^11.3.4",
22
22
  "@ms-cloudpack/path-string-parsing": "^1.2.6",
23
23
  "@ms-cloudpack/path-utilities": "^3.0.4",
24
- "@ms-cloudpack/remote-cache": "^0.10.10",
24
+ "@ms-cloudpack/remote-cache": "^0.10.11",
25
25
  "@ms-cloudpack/setup-utilities": "^0.5.14",
26
26
  "@ms-cloudpack/task-reporter": "^0.15.1",
27
27
  "@ms-cloudpack/telemetry": "^0.10.14",
@@ -1 +0,0 @@
1
- {"version":3,"file":"discoverAppPaths.d.ts","sourceRoot":"","sources":["../../src/utilities/discoverAppPaths.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAEnE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,kCAAkC,CAAC;AAE7E,MAAM,MAAM,sBAAsB,GAAG,KAAK,CAAC;AAE3C;;;;;;;GAOG;AACH,wBAAsB,gBAAgB,CAAC,MAAM,EAAE;IAC7C,uCAAuC;IACvC,GAAG,EAAE,MAAM,CAAC;IAEZ;;;OAGG;IACH,QAAQ,CAAC,EAAE,oBAAoB,CAAC;IAEhC;;;;;OAKG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,GAAG,OAAO,CAAC,MAAM,EAAE,GAAG,iBAAiB,CAAC,CAiFxC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"discoverAppPaths.js","sourceRoot":"","sources":["../../src/utilities/discoverAppPaths.ts"],"names":[],"mappings":"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","sourcesContent":["import { PackageDefinitions } from '@ms-cloudpack/package-utilities';\nimport glob from 'fast-glob';\nimport fs from 'fs';\nimport path from 'path';\nimport prompts, { type Choice } from 'prompts';\nimport type { CommandExitParams } from '../types/CommandAction.js';\nimport { appConfigFileName } from '@ms-cloudpack/config';\nimport type { AppPathDiscoveryMode } from '../types/AppPathDiscoveryMode.js';\n\nexport type _AppPromptQuestionName = 'app';\n\n/**\n * Gets the appPath from which Cloudpack will run. If the CWD is a Cloudpack-enabled app,\n * we'll use that; otherwise, we'll scan for Cloudpack-enabled app and present the user\n * with a menu. If no apps are found, Cloudpack will just try to run in the CWD anyway.\n *\n * @returns App path(s) (just one unless `discover: 'multi'`), or an exit options object if\n * there was an error.\n */\nexport async function discoverAppPaths(params: {\n /** Working directory to start from. */\n cwd: string;\n\n /**\n * How to determine the app path(s). (`--app` in the docs refers to `desiredApp` here.)\n * @default 'single'\n */\n discover?: AppPathDiscoveryMode;\n\n /**\n * Desired app name or substring, from the `--app` option.\n * - If there's an exact match, only that app will be returned.\n * - If multiple apps match a substring, see `discover` for behavior.\n * - If no match, it's an error.\n */\n desiredApp?: string;\n}): Promise<string[] | CommandExitParams> {\n const { cwd, desiredApp, discover } = params;\n const multiApp = discover === 'multi';\n\n if (!desiredApp && fs.existsSync(path.join(cwd, appConfigFileName))) {\n // If no specific app was requested, and the cwd is a cloudpack app, just use that.\n return [cwd];\n }\n\n // Get all cloudpack app paths based on the presence of cloudpack.config.json\n const cloudpackAppPaths = (glob.sync([`**/${appConfigFileName}`], { cwd, ignore: ['**/node_modules/**'] }) ?? []).map(\n (file) => path.join(cwd, path.dirname(file)),\n );\n\n if (!cloudpackAppPaths.length) {\n // Include the cwd if there are no configs found, since it's possible to run start or init\n // without a config.\n cloudpackAppPaths.push(cwd);\n }\n\n if (!desiredApp && (multiApp || cloudpackAppPaths.length === 1)) {\n // Return all apps found if we're in multi-app mode or only one app was found\n // (and no specific app was requested).\n return cloudpackAppPaths;\n }\n\n // Get each app's name and description, filtered by `desiredApp` if specified.\n // (These use Choice format in case they're later used in a prompt.)\n const packages = new PackageDefinitions();\n const appChoices = (\n await Promise.all<Omit<Choice, 'value'> & { value: string }>(\n cloudpackAppPaths.map(async (dir) => {\n const pkg = await packages.get(dir);\n return {\n title: pkg.name,\n description: pkg?.description ?? 'An awesome app that would be even more awesome with a proper description',\n value: dir,\n };\n }),\n )\n )\n .filter((choice) => !desiredApp || choice.title.includes(desiredApp))\n .sort((c1, c2) => c1.title.localeCompare(c2.title));\n\n // Figure out if there are any matches for `desiredApp`\n if (desiredApp) {\n if (!appChoices.length) {\n return {\n message: `No Cloudpack apps found matching the name \"${desiredApp}\".`,\n hasErrors: true,\n };\n }\n\n // Prefer an exact match\n const exactMatch = appChoices.find((choice) => choice.title === desiredApp);\n if (exactMatch) {\n return [exactMatch.value];\n }\n\n // If there's no exact match, it means at least one substring match was found\n if (multiApp || appChoices.length === 1) {\n // Return them all if we're in multi-app mode or only one match was found\n return appChoices.map((choice) => choice.value);\n }\n }\n\n // There are multiple candidates, so prompt the user to choose one\n // (implicitly, we're in single-app mode if we reach here)\n const response = await prompts<_AppPromptQuestionName>({\n type: 'select',\n name: 'app',\n message: 'Select the app you want to start',\n choices: appChoices,\n });\n\n // This will be undefined if the user cancels the prompt\n if (!response.app) {\n return { isInterrupted: true, message: '' };\n }\n\n return [response.app as string];\n}\n"]}