diff --git a/client/packages/cli/index.js b/client/packages/cli/index.js index 495edecd9..90c52365a 100644 --- a/client/packages/cli/index.js +++ b/client/packages/cli/index.js @@ -1,9 +1,10 @@ // @ts-check import version from "./src/version.js"; -import { mkdir, writeFile, readFile, stat } from "fs/promises"; +import { mkdir, writeFile, readFile } from "fs/promises"; import { join } from "path"; import { randomUUID } from "crypto"; +import jsonDiff from "json-diff"; import dotenv from "dotenv"; import chalk from "chalk"; import { program, Option } from "commander"; @@ -1070,10 +1071,27 @@ async function pushPerms(appId) { return; } - const ok = await promptOk( - "Pushing permissions rules. This will immediately replace your production rules. OK to proceed?", - ); - if (!ok) return; + console.log("Planning..."); + + const prodPerms = await fetchJson({ + path: `/dash/apps/${appId}/perms/pull`, + debugName: "Perms pull", + errorMessage: "Failed to pull perms.", + }); + + if (!prodPerms.ok) return; + + const diffedStr = jsonDiff.diffString(prodPerms.data.perms, perms) + if (!diffedStr.length) { + console.log("No perms changes detected. Exiting."); + return; + } + + console.log("The following changes will be applied to your perms:"); + console.log(diffedStr); + + const okPush = await promptOk("OK to proceed?"); + if (!okPush) return; const permsRes = await fetchJson({ method: "POST", diff --git a/client/packages/cli/package.json b/client/packages/cli/package.json index 7c327e626..6c660e229 100644 --- a/client/packages/cli/package.json +++ b/client/packages/cli/package.json @@ -16,11 +16,15 @@ "dotenv": "^16.3.1", "env-paths": "^3.0.0", "inquirer": "^10.1.6", + "json-diff": "^1.0.6", "open": "^10.1.0", "ora": "^8.1.1", "pkg-dir": "^8.0.0", "prettier": "^3.3.3", "terminal-link": "^3.0.0", "unconfig": "^0.5.5" + }, + "devDependencies": { + "@types/json-diff": "^1.0.3" } } diff --git a/client/pnpm-lock.yaml b/client/pnpm-lock.yaml index cd3c23e8b..673427313 100644 --- a/client/pnpm-lock.yaml +++ b/client/pnpm-lock.yaml @@ -60,6 +60,9 @@ importers: inquirer: specifier: ^10.1.6 version: 10.1.8 + json-diff: + specifier: ^1.0.6 + version: 1.0.6 open: specifier: ^10.1.0 version: 10.1.0 @@ -78,6 +81,10 @@ importers: unconfig: specifier: ^0.5.5 version: 0.5.5 + devDependencies: + '@types/json-diff': + specifier: ^1.0.3 + version: 1.0.3 packages/core: dependencies: @@ -4279,6 +4286,12 @@ packages: levn: 0.4.1 dev: true + /@ewoudenberg/difflib@0.1.0: + resolution: {integrity: sha512-OU5P5mJyD3OoWYMWY+yIgwvgNS9cFAU10f+DDuvtogcWQOoJIsQ4Hy2McSfUfhKjq8L0FuWVb4Rt7kgA+XK86A==} + dependencies: + heap: 0.2.7 + dev: false + /@expo/bunyan@4.0.0: resolution: {integrity: sha512-Ydf4LidRB/EBI+YrB+cVLqIseiRfjUI/AeHBgjGMtq3GroraDu81OV7zqophRgupngoL3iS3JUMDMnxO7g39qA==} engines: {'0': node >=0.10.0} @@ -7344,6 +7357,10 @@ packages: parse5: 7.2.1 dev: true + /@types/json-diff@1.0.3: + resolution: {integrity: sha512-Qvxm8fpRMv/1zZR3sQWImeRK2mBYJji20xF51Fq9Gt//Ed18u0x6/FNLogLS1xhfUWTEmDyqveJqn95ltB6Kvw==} + dev: true + /@types/json-schema@7.0.15: resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} @@ -8823,6 +8840,11 @@ packages: resolution: {integrity: sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g==} dev: false + /colors@1.4.0: + resolution: {integrity: sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==} + engines: {node: '>=0.1.90'} + dev: false + /combined-stream@1.0.8: resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} engines: {node: '>= 0.8'} @@ -9535,6 +9557,13 @@ packages: resolution: {integrity: sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==} engines: {node: '>=12'} + /dreamopt@0.8.0: + resolution: {integrity: sha512-vyJTp8+mC+G+5dfgsY+r3ckxlz+QMX40VjPQsZc5gxVAxLmi64TBoVkP54A/pRAXMXsbu2GMMBrZPxNv23waMg==} + engines: {node: '>=0.4.0'} + dependencies: + wordwrap: 1.0.0 + dev: false + /eastasianwidth@0.2.0: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} @@ -11135,6 +11164,10 @@ packages: dependencies: function-bind: 1.1.2 + /heap@0.2.7: + resolution: {integrity: sha512-2bsegYkkHO+h/9MGbn6KWcE45cHZgPANo5LXF7EvWdT0yT2EguSVO1nDgU5c8+ZOPwp2vMNa7YFsJhVcDR9Sdg==} + dev: false + /hermes-estree@0.23.1: resolution: {integrity: sha512-eT5MU3f5aVhTqsfIReZ6n41X5sYn4IdQL0nvz6yO+MMlPxw49aSARHLg/MSehQftyjnrE8X6bYregzSumqc6cg==} dev: false @@ -12463,6 +12496,15 @@ packages: resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} dev: true + /json-diff@1.0.6: + resolution: {integrity: sha512-tcFIPRdlc35YkYdGxcamJjllUhXWv4n2rK9oJ2RsAzV4FBkuV4ojKEDgcZ+kpKxDmJKv+PFK65+1tVVOnSeEqA==} + hasBin: true + dependencies: + '@ewoudenberg/difflib': 0.1.0 + colors: 1.4.0 + dreamopt: 0.8.0 + dev: false + /json-parse-better-errors@1.0.2: resolution: {integrity: sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==} @@ -16876,6 +16918,10 @@ packages: resolution: {integrity: sha512-CjpbqNtBGNAeyNS/9W6q3kSkKE52+FjIj7AkFlLr11s/VWGUu6a2CdYSdGxocIhIVjaW/zchesBQUKPVU69Cqg==} dev: false + /wordwrap@1.0.0: + resolution: {integrity: sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==} + dev: false + /wrap-ansi@6.2.0: resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==} engines: {node: '>=8'}