@geekmidas/cli 10.0.0-alpha.111 → 10.0.0-alpha.113

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 (37) hide show
  1. package/dist/{cli-Br5ApIgR.mjs → cli-DDY3jfTt.mjs} +3 -3
  2. package/dist/{cli-Br5ApIgR.mjs.map → cli-DDY3jfTt.mjs.map} +1 -1
  3. package/dist/{eas-BkLA60P2.cjs → eas-Cne743nQ.cjs} +21 -3
  4. package/dist/eas-Cne743nQ.cjs.map +1 -0
  5. package/dist/{eas-6ezdJtry.mjs → eas-DEpwISrQ.mjs} +25 -7
  6. package/dist/eas-DEpwISrQ.mjs.map +1 -0
  7. package/dist/{github-D2eABlxM.mjs → github-BMakI-k3.mjs} +5 -4
  8. package/dist/github-BMakI-k3.mjs.map +1 -0
  9. package/dist/{github-DDOHjdS9.cjs → github-C3gblUvr.cjs} +5 -3
  10. package/dist/github-C3gblUvr.cjs.map +1 -0
  11. package/dist/{googlePlay-DNgybe5t.cjs → googlePlay-B6uiHi65.cjs} +2 -2
  12. package/dist/{googlePlay-DNgybe5t.cjs.map → googlePlay-B6uiHi65.cjs.map} +1 -1
  13. package/dist/{googlePlay-DY9vZQ1p.mjs → googlePlay-BYZ-J5sC.mjs} +4 -4
  14. package/dist/{googlePlay-DY9vZQ1p.mjs.map → googlePlay-BYZ-J5sC.mjs.map} +1 -1
  15. package/dist/index.cjs +167 -74
  16. package/dist/index.cjs.map +1 -1
  17. package/dist/index.mjs +176 -85
  18. package/dist/index.mjs.map +1 -1
  19. package/dist/{migrate-B9GswIAr.mjs → migrate-xHYaeBkd.mjs} +2 -2
  20. package/dist/{migrate-B9GswIAr.mjs.map → migrate-xHYaeBkd.mjs.map} +1 -1
  21. package/dist/{publish-B-EIjfQ0.mjs → publish-CSctCNf4.mjs} +2 -2
  22. package/dist/{publish-B-EIjfQ0.mjs.map → publish-CSctCNf4.mjs.map} +1 -1
  23. package/dist/{publish-CPgSbtcs.cjs → publish-SDG1WfYn.cjs} +2 -2
  24. package/dist/{publish-CPgSbtcs.cjs.map → publish-SDG1WfYn.cjs.map} +1 -1
  25. package/dist/serverSetup--O61SRvg.mjs +558 -0
  26. package/dist/serverSetup--O61SRvg.mjs.map +1 -0
  27. package/dist/serverSetup-BCbD8ksJ.cjs +558 -0
  28. package/dist/serverSetup-BCbD8ksJ.cjs.map +1 -0
  29. package/dist/{stage-DjxR_7C0.mjs → stage-ClKTHQoM.mjs} +2 -2
  30. package/dist/{stage-DjxR_7C0.mjs.map → stage-ClKTHQoM.mjs.map} +1 -1
  31. package/dist/{terminal-mXM-Lqc6.mjs → terminal-CybB-cjk.mjs} +2 -2
  32. package/dist/{terminal-mXM-Lqc6.mjs.map → terminal-CybB-cjk.mjs.map} +1 -1
  33. package/package.json +15 -15
  34. package/dist/eas-6ezdJtry.mjs.map +0 -1
  35. package/dist/eas-BkLA60P2.cjs.map +0 -1
  36. package/dist/github-D2eABlxM.mjs.map +0 -1
  37. package/dist/github-DDOHjdS9.cjs.map +0 -1
package/dist/index.cjs CHANGED
@@ -57,7 +57,7 @@ crypto = require_rolldown_runtime.__toESM(crypto, 1);
57
57
  let _geekmidas_constructs_functions = require("@geekmidas/constructs/functions");
58
58
  let _geekmidas_constructs_topic = require("@geekmidas/constructs/topic");
59
59
  //#region package.json
60
- var version = "10.0.0-alpha.111";
60
+ var version = "10.0.0-alpha.113";
61
61
  //#endregion
62
62
  //#region src/prompt.ts
63
63
  /**
@@ -5949,25 +5949,25 @@ function loadPackageJson() {
5949
5949
  * Run: pnpm --filter @geekmidas/cli sync-versions
5950
5950
  */
5951
5951
  const GEEKMIDAS_VERSIONS = {
5952
- "@geekmidas/audit": "~10.0.0-alpha.111",
5953
- "@geekmidas/auth": "~10.0.0-alpha.111",
5954
- "@geekmidas/cache": "~10.0.0-alpha.111",
5955
- "@geekmidas/client": "~10.0.0-alpha.111",
5956
- "@geekmidas/cloud": "~10.0.0-alpha.111",
5957
- "@geekmidas/constructs": "~10.0.0-alpha.111",
5958
- "@geekmidas/db": "~10.0.0-alpha.111",
5959
- "@geekmidas/emailkit": "~10.0.0-alpha.111",
5960
- "@geekmidas/envkit": "~10.0.0-alpha.111",
5961
- "@geekmidas/errors": "~10.0.0-alpha.111",
5962
- "@geekmidas/events": "~10.0.0-alpha.111",
5963
- "@geekmidas/logger": "~10.0.0-alpha.111",
5964
- "@geekmidas/manifest": "~10.0.0-alpha.111",
5965
- "@geekmidas/rate-limit": "~10.0.0-alpha.111",
5966
- "@geekmidas/schema": "~10.0.0-alpha.111",
5967
- "@geekmidas/services": "~10.0.0-alpha.111",
5968
- "@geekmidas/storage": "~10.0.0-alpha.111",
5969
- "@geekmidas/telescope": "~10.0.0-alpha.111",
5970
- "@geekmidas/testkit": "~10.0.0-alpha.111",
5952
+ "@geekmidas/audit": "~10.0.0-alpha.113",
5953
+ "@geekmidas/auth": "~10.0.0-alpha.113",
5954
+ "@geekmidas/cache": "~10.0.0-alpha.113",
5955
+ "@geekmidas/client": "~10.0.0-alpha.113",
5956
+ "@geekmidas/cloud": "~10.0.0-alpha.113",
5957
+ "@geekmidas/constructs": "~10.0.0-alpha.113",
5958
+ "@geekmidas/db": "~10.0.0-alpha.113",
5959
+ "@geekmidas/emailkit": "~10.0.0-alpha.113",
5960
+ "@geekmidas/envkit": "~10.0.0-alpha.113",
5961
+ "@geekmidas/errors": "~10.0.0-alpha.113",
5962
+ "@geekmidas/events": "~10.0.0-alpha.113",
5963
+ "@geekmidas/logger": "~10.0.0-alpha.113",
5964
+ "@geekmidas/manifest": "~10.0.0-alpha.113",
5965
+ "@geekmidas/rate-limit": "~10.0.0-alpha.113",
5966
+ "@geekmidas/schema": "~10.0.0-alpha.113",
5967
+ "@geekmidas/services": "~10.0.0-alpha.113",
5968
+ "@geekmidas/storage": "~10.0.0-alpha.113",
5969
+ "@geekmidas/telescope": "~10.0.0-alpha.113",
5970
+ "@geekmidas/testkit": "~10.0.0-alpha.113",
5971
5971
  "@geekmidas/cli": `~${loadPackageJson().version}`
5972
5972
  };
5973
5973
  //#endregion
@@ -7160,7 +7160,7 @@ const COMMIT = /^[0-9a-f]{40}$/;
7160
7160
  * The `uses:` value for the stages action, with a comment saying which CLI
7161
7161
  * release the pinned commit is.
7162
7162
  */
7163
- function stagesActionUses(commit = "8a63c47fd347367a03f2dfe1c3ea031556ede424", version = cliVersion()) {
7163
+ function stagesActionUses(commit = "18d6b7860652d3db231d361933ee2d5ec10f0941", version = cliVersion()) {
7164
7164
  return commit && COMMIT.test(commit) ? `${STAGES_ACTION}@${commit} # @geekmidas/cli ${version}` : `${STAGES_ACTION}@main # pin to a commit SHA: see the action's README`;
7165
7165
  }
7166
7166
  //#endregion
@@ -7627,6 +7627,7 @@ ${registryLogin(registry)}
7627
7627
  # pinned host key (DEPLOY_KNOWN_HOSTS, a variable) on each environment:
7628
7628
  # never accepted on first sight. The server — user and host — is
7629
7629
  # deploy.compose.server in gkm.config.ts and the stage's GKM_SERVER_IPV4.
7630
+ # \`gkm compose:server --stage <stage>\` sets the server up and gives both.
7630
7631
  - name: SSH to the server
7631
7632
  run: |
7632
7633
  mkdir -p ~/.ssh && chmod 700 ~/.ssh
@@ -7659,26 +7660,6 @@ ${registryLogin(registry)}
7659
7660
  SHA: \${{ steps.commit.outputs.sha }}
7660
7661
  GODADDY_API_TOKEN: \${{ secrets.GODADDY_API_TOKEN }}
7661
7662
  HOSTINGER_API_TOKEN: \${{ secrets.HOSTINGER_API_TOKEN }}
7662
- ${options.mobileApp ? publishMobile(pm.exec) : ""}`;
7663
- }
7664
- /**
7665
- * The phone app, once its stage's servers run this release: its values
7666
- * synced to the stage's EAS environment, then an update on the stage's
7667
- * channel when a store build has its native code, or a store build
7668
- * submitted to the stores when none does (\`gkm publish\`). The build runs
7669
- * on EAS; this step only starts it.
7670
- */
7671
- function publishMobile(exec) {
7672
- return `
7673
- # The phone app, after its servers: an update when a store build has
7674
- # this native code, a store build submitted to the stores when none
7675
- # does. EXPO_TOKEN is a secret on the stage's environment (an EAS
7676
- # access token); the build runs on EAS, not here.
7677
- - name: Publish the app
7678
- run: ${exec} gkm publish --stage "$STAGE"
7679
- env:
7680
- STAGE: \${{ matrix.stage }}
7681
- EXPO_TOKEN: \${{ secrets.EXPO_TOKEN }}
7682
7663
  `;
7683
7664
  }
7684
7665
  /**
@@ -7784,6 +7765,97 @@ function generateGithubFiles(options) {
7784
7765
  return files;
7785
7766
  }
7786
7767
  //#endregion
7768
+ //#region src/mobile/easWorkflow.ts
7769
+ /**
7770
+ * A stage's EAS workflow (`.eas/workflows/publish-<stage>.yml`): what
7771
+ * `gkm publish` does, run by EAS itself — so shipping the app needs no CI
7772
+ * of the project's own, no runner and no token in GitHub.
7773
+ *
7774
+ * Per platform: the native code's fingerprint, read with the stage's EAS
7775
+ * environment; a finished store build of the stage's profile with that
7776
+ * fingerprint; then an update on the stage's channel when there is one, or
7777
+ * a store build, submitted with the stage's submit profile, when there is
7778
+ * not. iOS is submitted once `submit.<stage>.ios.ascAppId` is set — until
7779
+ * then it is built and not submitted.
7780
+ *
7781
+ * It runs when the stage is deployed: the protected stage on a release tag
7782
+ * (`v*`), every other deployed stage on a push to `main` — and on demand,
7783
+ * `eas workflow:run .eas/workflows/publish-<stage>.yml`. The values a build
7784
+ * reads are the stage's EAS environment, which `gkm eas:sync` keeps.
7785
+ *
7786
+ * Generated: written by `gkm eas:sync`, and overwritten by the next one.
7787
+ */
7788
+ /** Where a stage's workflow is written, relative to the app. */
7789
+ function easWorkflowPath(stage) {
7790
+ return `.eas/workflows/publish-${stage}.yml`;
7791
+ }
7792
+ /** The stage's EAS workflow, as YAML. */
7793
+ function easWorkflow(stage, options) {
7794
+ const profile = stage.stage;
7795
+ const jobs = { fingerprint: {
7796
+ name: "Fingerprint",
7797
+ type: "fingerprint",
7798
+ environment: stage.environment
7799
+ } };
7800
+ for (const platform of ["android", "ios"]) {
7801
+ const existing = `get_${platform}_build`;
7802
+ const build = `build_${platform}`;
7803
+ const name = platform === "ios" ? "iOS" : "Android";
7804
+ jobs[existing] = {
7805
+ name: `Find an ${name} store build with this native code`,
7806
+ needs: ["fingerprint"],
7807
+ type: "get-build",
7808
+ params: {
7809
+ fingerprint_hash: `\${{ needs.fingerprint.outputs.${platform}_fingerprint_hash }}`,
7810
+ profile,
7811
+ platform,
7812
+ distribution: "store"
7813
+ }
7814
+ };
7815
+ jobs[build] = {
7816
+ name: `Build ${name}`,
7817
+ needs: [existing],
7818
+ if: `\${{ !needs.${existing}.outputs.build_id }}`,
7819
+ type: "build",
7820
+ params: {
7821
+ platform,
7822
+ profile
7823
+ }
7824
+ };
7825
+ if (platform === "android" || options.iosSubmits) jobs[`submit_${platform}`] = {
7826
+ name: `Submit ${name}`,
7827
+ needs: [build],
7828
+ type: "submit",
7829
+ params: {
7830
+ build_id: `\${{ needs.${build}.outputs.build_id }}`,
7831
+ profile
7832
+ }
7833
+ };
7834
+ jobs[`update_${platform}`] = {
7835
+ name: `Update ${name} on '${stage.channel}'`,
7836
+ needs: [existing],
7837
+ if: `\${{ needs.${existing}.outputs.build_id }}`,
7838
+ type: "update",
7839
+ environment: stage.environment,
7840
+ params: {
7841
+ platform,
7842
+ channel: stage.channel
7843
+ }
7844
+ };
7845
+ }
7846
+ return `${[
7847
+ `# Generated by \`gkm eas:sync --stage ${stage.stage}\`: run it again rather than`,
7848
+ "# editing this file. An update when a store build has this native code,",
7849
+ `# a store build submitted to the stores when none does. Run by hand:`,
7850
+ `# eas workflow:run ${easWorkflowPath(stage.stage)}`,
7851
+ ""
7852
+ ].join("\n")}${(0, yaml.stringify)({
7853
+ name: `Publish to ${stage.stage}`,
7854
+ on: options.release ? { push: { tags: ["v*"] } } : { push: { branches: ["main"] } },
7855
+ jobs
7856
+ }, { lineWidth: 0 })}`;
7857
+ }
7858
+ //#endregion
7787
7859
  //#region src/mobile/stage.ts
7788
7860
  /** A `MobileApp`'s `stages` names a stage the project does not deploy. */
7789
7861
  var MobileAppStageUndeclared = class extends require_errors.GkmError {
@@ -8702,6 +8774,35 @@ export default function SigningInScreen() {
8702
8774
  </SafeAreaView>
8703
8775
  );
8704
8776
  }
8777
+ `;
8778
+ const appConstructTs = `import { MobileApp } from '@geekmidas/constructs/mobile-app';
8779
+ import { api } from './api.ts';
8780
+ import { auth } from './auth.ts';
8781
+ import { email } from './email.ts';
8782
+
8783
+ /**
8784
+ * The mobile app — a construct like a site, which is what makes it an app.
8785
+ *
8786
+ * \`.dependsOn()\` is the single fact behind what a mobile app otherwise has
8787
+ * written down by hand: its API and auth URLs, its URL scheme, the scheme in
8788
+ * the auth server's trusted origins, Better Auth's Expo plugin, sign-in links
8789
+ * a phone can open — and, on a local stage, the mailer's inbox, so a link sent
8790
+ * in development is read on the device.
8791
+ */
8792
+ export const app = new MobileApp('App', { path: 'apps/app' }).dependsOn([
8793
+ api,
8794
+ auth,
8795
+ email,
8796
+ ]);
8797
+ `;
8798
+ const gitignore = `node_modules/
8799
+ .expo/
8800
+ dist/
8801
+ *.log
8802
+ .env*.local
8803
+ ios/
8804
+ android/
8805
+ .eas/
8705
8806
  `;
8706
8807
  return [
8707
8808
  {
@@ -8716,6 +8817,13 @@ export default function SigningInScreen() {
8716
8817
  path: "apps/app/eas.json",
8717
8818
  content: `${JSON.stringify(easJson, null, 2)}\n`
8718
8819
  },
8820
+ ...stages.map((stage) => ({
8821
+ path: `apps/app/${easWorkflowPath(stage.stage)}`,
8822
+ content: easWorkflow(stage, {
8823
+ release: options.stages.protected?.includes(stage.stage) ?? false,
8824
+ iosSubmits: false
8825
+ })
8826
+ })),
8719
8827
  {
8720
8828
  path: "apps/app/babel.config.js",
8721
8829
  content: babelConfig
@@ -8806,38 +8914,11 @@ export default function SigningInScreen() {
8806
8914
  },
8807
8915
  {
8808
8916
  path: "apps/app/.gitignore",
8809
- content: `node_modules/
8810
- .expo/
8811
- dist/
8812
- *.log
8813
- .env*.local
8814
- ios/
8815
- android/
8816
- .eas/
8817
- `
8917
+ content: gitignore
8818
8918
  },
8819
8919
  {
8820
8920
  path: "constructs/app.ts",
8821
- content: `import { MobileApp } from '@geekmidas/constructs/mobile-app';
8822
- import { api } from './api.ts';
8823
- import { auth } from './auth.ts';
8824
- import { email } from './email.ts';
8825
-
8826
- /**
8827
- * The mobile app — a construct like a site, which is what makes it an app.
8828
- *
8829
- * \`.dependsOn()\` is the single fact behind what a mobile app otherwise has
8830
- * written down by hand: its API and auth URLs, its URL scheme, the scheme in
8831
- * the auth server's trusted origins, Better Auth's Expo plugin, sign-in links
8832
- * a phone can open — and, on a local stage, the mailer's inbox, so a link sent
8833
- * in development is read on the device.
8834
- */
8835
- export const app = new MobileApp('App', { path: 'apps/app' }).dependsOn([
8836
- api,
8837
- auth,
8838
- email,
8839
- ]);
8840
- `
8921
+ content: appConstructTs
8841
8922
  }
8842
8923
  ];
8843
8924
  }
@@ -16339,7 +16420,7 @@ program.command("eas:sync").description("Set up a mobile app's EAS project for a
16339
16420
  try {
16340
16421
  const globalOptions = program.opts();
16341
16422
  if (globalOptions.cwd) process.chdir(globalOptions.cwd);
16342
- const { easSync } = await Promise.resolve().then(() => require("./eas-BkLA60P2.cjs"));
16423
+ const { easSync } = await Promise.resolve().then(() => require("./eas-Cne743nQ.cjs"));
16343
16424
  await easSync(options);
16344
16425
  } catch (error) {
16345
16426
  exitWithError(error);
@@ -16349,7 +16430,7 @@ program.command("publish").description("Ship a mobile app for a deployed stage:
16349
16430
  try {
16350
16431
  const globalOptions = program.opts();
16351
16432
  if (globalOptions.cwd) process.chdir(globalOptions.cwd);
16352
- const { publish, PublishModeConflict } = await Promise.resolve().then(() => require("./publish-CPgSbtcs.cjs"));
16433
+ const { publish, PublishModeConflict } = await Promise.resolve().then(() => require("./publish-SDG1WfYn.cjs"));
16353
16434
  if (options.build && options.update) throw new PublishModeConflict();
16354
16435
  const { build, update, ...rest } = options;
16355
16436
  await publish({
@@ -16365,7 +16446,7 @@ program.command("deploy:google-play").description("Let EAS Submit publish a mobi
16365
16446
  try {
16366
16447
  const globalOptions = program.opts();
16367
16448
  if (globalOptions.cwd) process.chdir(globalOptions.cwd);
16368
- const { deployGooglePlay } = await Promise.resolve().then(() => require("./googlePlay-DNgybe5t.cjs"));
16449
+ const { deployGooglePlay } = await Promise.resolve().then(() => require("./googlePlay-B6uiHi65.cjs"));
16369
16450
  await deployGooglePlay(options);
16370
16451
  } catch (error) {
16371
16452
  exitWithError(error);
@@ -16640,6 +16721,16 @@ program.command("deploy:rollback").description("Put a stage's app back on its pr
16640
16721
  exitWithError(error);
16641
16722
  }
16642
16723
  });
16724
+ program.command("compose:server").description("Set up a stage's server for compose deploys: harden it (SSH keys only, no root login, firewall, security updates, fail2ban), install Docker, create the deploy user, and give its key to GitHub").requiredOption("--stage <stage>", "A deployed stage from gkm.config.ts").option("--admin <user>", "The sudo user you log in to the server as — never root (asked when absent)").option("--key-file <path>", "The deploy key pair (default: ~/.ssh/gkm-<project>-<stage>)").option("--repo <owner/name>", "GitHub repository (default: this one)").option("--no-github", "Leave the GitHub environment's key and host alone").option("--yes", "Set the server up without asking first").option("--dry-run", "Print the plan and the script; connect to nothing").action(async (options) => {
16725
+ try {
16726
+ const globalOptions = program.opts();
16727
+ if (globalOptions.cwd) process.chdir(globalOptions.cwd);
16728
+ const { composeServerCommand } = await Promise.resolve().then(() => require("./serverSetup-BCbD8ksJ.cjs"));
16729
+ await composeServerCommand(options);
16730
+ } catch (error) {
16731
+ exitWithError(error);
16732
+ }
16733
+ });
16643
16734
  program.command("deploy:init").description("Initialize Dokploy deployment (create project and application)").option("--endpoint <url>", "Dokploy server URL (uses stored credentials if logged in)").requiredOption("--project <name>", "Project name (creates if not exists)").requiredOption("--app <name>", "Application name").option("--project-id <id>", "Use existing project ID instead of creating").option("--registry-id <id>", "Configure registry for the application").action(async (options) => {
16644
16735
  try {
16645
16736
  const globalOptions = program.opts();
@@ -16659,7 +16750,7 @@ program.command("deploy:github").description("Let GitHub Actions deploy a stage:
16659
16750
  try {
16660
16751
  const globalOptions = program.opts();
16661
16752
  if (globalOptions.cwd) process.chdir(globalOptions.cwd);
16662
- const { deployGithubCommand } = await Promise.resolve().then(() => require("./github-DDOHjdS9.cjs"));
16753
+ const { deployGithubCommand } = await Promise.resolve().then(() => require("./github-C3gblUvr.cjs"));
16663
16754
  await deployGithubCommand(options);
16664
16755
  } catch (error) {
16665
16756
  exitWithError(error);
@@ -16839,6 +16930,8 @@ try {
16839
16930
  program.parse();
16840
16931
  //#endregion
16841
16932
  exports.canPrompt = canPrompt;
16933
+ exports.easWorkflow = easWorkflow;
16934
+ exports.easWorkflowPath = easWorkflowPath;
16842
16935
  exports.formatError = formatError;
16843
16936
  exports.generateFullstackCustomSecrets = generateFullstackCustomSecrets;
16844
16937
  exports.mobileStage = mobileStage;