@geekmidas/cli 10.0.0-alpha.105 → 10.0.0-alpha.106

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 (101) hide show
  1. package/dist/{GoDaddyProvider-Cr9Uvqyz.cjs → GoDaddyProvider-BesL1P15.cjs} +2 -2
  2. package/dist/{GoDaddyProvider-Cr9Uvqyz.cjs.map → GoDaddyProvider-BesL1P15.cjs.map} +1 -1
  3. package/dist/{GoDaddyProvider-DjtX8TUM.mjs → GoDaddyProvider-DufGBcDt.mjs} +2 -2
  4. package/dist/{GoDaddyProvider-DjtX8TUM.mjs.map → GoDaddyProvider-DufGBcDt.mjs.map} +1 -1
  5. package/dist/{LegacyStateStore-D-0XrizH.mjs → LegacyStateStore-1kOwqcd_.mjs} +3 -3
  6. package/dist/{LegacyStateStore-D-0XrizH.mjs.map → LegacyStateStore-1kOwqcd_.mjs.map} +1 -1
  7. package/dist/{LegacyStateStore-CnxFZGeQ.cjs → LegacyStateStore-aFp6-7im.cjs} +3 -3
  8. package/dist/{LegacyStateStore-CnxFZGeQ.cjs.map → LegacyStateStore-aFp6-7im.cjs.map} +1 -1
  9. package/dist/{LocalStateStore-dVcU5RNe.mjs → LocalStateStore-DFGsiLDy.mjs} +2 -2
  10. package/dist/{LocalStateStore-dVcU5RNe.mjs.map → LocalStateStore-DFGsiLDy.mjs.map} +1 -1
  11. package/dist/{LocalStateStore-DGR_KzjD.cjs → LocalStateStore-Fo33UPTI.cjs} +2 -2
  12. package/dist/{LocalStateStore-DGR_KzjD.cjs.map → LocalStateStore-Fo33UPTI.cjs.map} +1 -1
  13. package/dist/{S3StateStore-DIyP76Kb.mjs → S3StateStore-BlwEPivO.mjs} +2 -2
  14. package/dist/{S3StateStore-DIyP76Kb.mjs.map → S3StateStore-BlwEPivO.mjs.map} +1 -1
  15. package/dist/{S3StateStore-D8z0z8P2.cjs → S3StateStore-ZWXXuNQp.cjs} +2 -2
  16. package/dist/{S3StateStore-D8z0z8P2.cjs.map → S3StateStore-ZWXXuNQp.cjs.map} +1 -1
  17. package/dist/{SSMStateStore-CIOsbEcQ.cjs → SSMStateStore-D5ej5j5M.cjs} +2 -2
  18. package/dist/{SSMStateStore-CIOsbEcQ.cjs.map → SSMStateStore-D5ej5j5M.cjs.map} +1 -1
  19. package/dist/{SSMStateStore-B7J_fv0d.mjs → SSMStateStore-DG9h2iVY.mjs} +2 -2
  20. package/dist/{SSMStateStore-B7J_fv0d.mjs.map → SSMStateStore-DG9h2iVY.mjs.map} +1 -1
  21. package/dist/{add-CC69Yf5t.mjs → add-1VSxmKnf.mjs} +3 -3
  22. package/dist/{add-CC69Yf5t.mjs.map → add-1VSxmKnf.mjs.map} +1 -1
  23. package/dist/{add-DWj9Kccz.cjs → add-B9IgkvTU.cjs} +3 -3
  24. package/dist/{add-DWj9Kccz.cjs.map → add-B9IgkvTU.cjs.map} +1 -1
  25. package/dist/{appPorts-C9z9Pzn9.mjs → appPorts-BoXMwolc.mjs} +32 -6
  26. package/dist/appPorts-BoXMwolc.mjs.map +1 -0
  27. package/dist/{appPorts-Cu79hJF6.cjs → appPorts-IW-OZmRi.cjs} +37 -5
  28. package/dist/appPorts-IW-OZmRi.cjs.map +1 -0
  29. package/dist/{bundler-TZ72P7LF.cjs → bundler-BBDrSnvE.cjs} +5 -5
  30. package/dist/{bundler-TZ72P7LF.cjs.map → bundler-BBDrSnvE.cjs.map} +1 -1
  31. package/dist/{bundler-BpYpp1Hf.mjs → bundler-By29I7km.mjs} +5 -5
  32. package/dist/{bundler-BpYpp1Hf.mjs.map → bundler-By29I7km.mjs.map} +1 -1
  33. package/dist/{cli-iqNUZ9Va.cjs → cli-Btfl8J6K.cjs} +2 -2
  34. package/dist/{cli-iqNUZ9Va.cjs.map → cli-Btfl8J6K.cjs.map} +1 -1
  35. package/dist/{cli-BZ_9cc0O.mjs → cli-D-ZAyAub.mjs} +2 -2
  36. package/dist/{cli-BZ_9cc0O.mjs.map → cli-D-ZAyAub.mjs.map} +1 -1
  37. package/dist/{compose-BXUDOrte.mjs → compose-C-lnkCAT.mjs} +3 -3
  38. package/dist/{compose-BXUDOrte.mjs.map → compose-C-lnkCAT.mjs.map} +1 -1
  39. package/dist/{compose-5b4lzIyr.cjs → compose-daUOp1bm.cjs} +3 -3
  40. package/dist/{compose-5b4lzIyr.cjs.map → compose-daUOp1bm.cjs.map} +1 -1
  41. package/dist/deploy/public.cjs +6 -6
  42. package/dist/deploy/public.mjs +6 -6
  43. package/dist/{deploy-BXx5PHR8.mjs → deploy-T3TwqzKf.mjs} +5 -5
  44. package/dist/{deploy-BXx5PHR8.mjs.map → deploy-T3TwqzKf.mjs.map} +1 -1
  45. package/dist/{deploy-rdTC6BqI.cjs → deploy-V43Rbboj.cjs} +5 -5
  46. package/dist/{deploy-rdTC6BqI.cjs.map → deploy-V43Rbboj.cjs.map} +1 -1
  47. package/dist/{dns-CRungu5C.mjs → dns-AosA2wwP.mjs} +2 -2
  48. package/dist/{dns-CRungu5C.mjs.map → dns-AosA2wwP.mjs.map} +1 -1
  49. package/dist/{dns-FMg7REGo.cjs → dns-BfNzYlpR.cjs} +2 -2
  50. package/dist/{dns-FMg7REGo.cjs.map → dns-BfNzYlpR.cjs.map} +1 -1
  51. package/dist/{dokploy-U_yXwsT7.cjs → dokploy-COnyBUBW.cjs} +2 -2
  52. package/dist/{dokploy-U_yXwsT7.cjs.map → dokploy-COnyBUBW.cjs.map} +1 -1
  53. package/dist/{dokploy-CuluaeVl.mjs → dokploy-CaLl5YmO.mjs} +2 -2
  54. package/dist/{dokploy-CuluaeVl.mjs.map → dokploy-CaLl5YmO.mjs.map} +1 -1
  55. package/dist/{encryption-XqokmrEn.mjs → encryption-BqSWtrXU.mjs} +2 -2
  56. package/dist/{encryption-XqokmrEn.mjs.map → encryption-BqSWtrXU.mjs.map} +1 -1
  57. package/dist/{encryption-D-louLFQ.cjs → encryption-CJdgXVFM.cjs} +2 -2
  58. package/dist/{encryption-D-louLFQ.cjs.map → encryption-CJdgXVFM.cjs.map} +1 -1
  59. package/dist/{engine-DqNljyye.mjs → engine-BMM2Vy26.mjs} +3 -3
  60. package/dist/{engine-DqNljyye.mjs.map → engine-BMM2Vy26.mjs.map} +1 -1
  61. package/dist/{engine-BdpcrYWi.cjs → engine-DjI9DFDW.cjs} +3 -3
  62. package/dist/{engine-BdpcrYWi.cjs.map → engine-DjI9DFDW.cjs.map} +1 -1
  63. package/dist/{github-CA33zfqv.cjs → github-MYWre3_E.cjs} +4 -4
  64. package/dist/{github-CA33zfqv.cjs.map → github-MYWre3_E.cjs.map} +1 -1
  65. package/dist/{github-b_kS4jvw.mjs → github-SViQU_St.mjs} +4 -4
  66. package/dist/{github-b_kS4jvw.mjs.map → github-SViQU_St.mjs.map} +1 -1
  67. package/dist/index.cjs +49 -49
  68. package/dist/index.cjs.map +1 -1
  69. package/dist/index.mjs +49 -49
  70. package/dist/index.mjs.map +1 -1
  71. package/dist/{migrate-DBp_H1fe.mjs → migrate-BNyMi8h5.mjs} +2 -2
  72. package/dist/{migrate-DBp_H1fe.mjs.map → migrate-BNyMi8h5.mjs.map} +1 -1
  73. package/dist/{migrate-BVMk0jtV.cjs → migrate-CNQp-SAH.cjs} +2 -2
  74. package/dist/{migrate-BVMk0jtV.cjs.map → migrate-CNQp-SAH.cjs.map} +1 -1
  75. package/dist/{migrate-Ln16jIxy.cjs → migrate-DwsOYzmN.cjs} +2 -2
  76. package/dist/{migrate-Ln16jIxy.cjs.map → migrate-DwsOYzmN.cjs.map} +1 -1
  77. package/dist/{migrate-DStsGGqC.mjs → migrate-H2vGmQ3l.mjs} +2 -2
  78. package/dist/{migrate-DStsGGqC.mjs.map → migrate-H2vGmQ3l.mjs.map} +1 -1
  79. package/dist/{resolve-DCdFajey.mjs → resolve-C2vVcD64.mjs} +3 -3
  80. package/dist/{resolve-DCdFajey.mjs.map → resolve-C2vVcD64.mjs.map} +1 -1
  81. package/dist/{resolve-CJ91HNQB.cjs → resolve-ClAnYHo-.cjs} +3 -3
  82. package/dist/{resolve-CJ91HNQB.cjs.map → resolve-ClAnYHo-.cjs.map} +1 -1
  83. package/dist/{rollback-CNS-52X9.mjs → rollback-BrBL9j9s.mjs} +4 -4
  84. package/dist/{rollback-CNS-52X9.mjs.map → rollback-BrBL9j9s.mjs.map} +1 -1
  85. package/dist/{rollback-UFitatDM.cjs → rollback-CRVwGkEl.cjs} +4 -4
  86. package/dist/{rollback-UFitatDM.cjs.map → rollback-CRVwGkEl.cjs.map} +1 -1
  87. package/dist/{seeds-BfzwCdYv.mjs → seeds-C1v4ZOro.mjs} +6 -6
  88. package/dist/seeds-C1v4ZOro.mjs.map +1 -0
  89. package/dist/{seeds-DkcKQ_F8.cjs → seeds-RTQPjA4K.cjs} +6 -6
  90. package/dist/seeds-RTQPjA4K.cjs.map +1 -0
  91. package/dist/{sniffer-B1neuJz2.mjs → sniffer-CLJ3cB3b.mjs} +6 -6
  92. package/dist/{sniffer-B1neuJz2.mjs.map → sniffer-CLJ3cB3b.mjs.map} +1 -1
  93. package/dist/{sniffer-DgfzmvB7.cjs → sniffer-Cy1pb4hg.cjs} +6 -6
  94. package/dist/{sniffer-DgfzmvB7.cjs.map → sniffer-Cy1pb4hg.cjs.map} +1 -1
  95. package/dist/target/public.cjs +1 -1
  96. package/dist/target/public.mjs +1 -1
  97. package/package.json +15 -15
  98. package/dist/appPorts-C9z9Pzn9.mjs.map +0 -1
  99. package/dist/appPorts-Cu79hJF6.cjs.map +0 -1
  100. package/dist/seeds-BfzwCdYv.mjs.map +0 -1
  101. package/dist/seeds-DkcKQ_F8.cjs.map +0 -1
@@ -1,6 +1,6 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  const require_define = require("../define-crmMcXFS.cjs");
3
- const require_resolve = require("../resolve-CJ91HNQB.cjs");
3
+ const require_resolve = require("../resolve-ClAnYHo-.cjs");
4
4
  const require_provider = require("../provider-BqpjG9QM.cjs");
5
5
  exports.DeployTargetNotYetSupported = require_define.DeployTargetNotYetSupported;
6
6
  exports.InvalidTargetOptions = require_resolve.InvalidTargetOptions;
@@ -1,4 +1,4 @@
1
1
  import { a as UnknownDeployTarget, i as DeployTargetNotYetSupported, n as isDeployTarget, t as defineTarget } from "../define-6poNqm5O.mjs";
2
- import { i as TargetRuntimeMismatch, l as TargetPackageNotFound, n as TargetEntryInvalid, r as TargetPackageInvalid, s as TargetRuntimeUndeclared, t as InvalidTargetOptions } from "../resolve-DCdFajey.mjs";
2
+ import { i as TargetRuntimeMismatch, l as TargetPackageNotFound, n as TargetEntryInvalid, r as TargetPackageInvalid, s as TargetRuntimeUndeclared, t as InvalidTargetOptions } from "../resolve-C2vVcD64.mjs";
3
3
  import { t as ProviderRemoved } from "../provider-CEOKk8NS.mjs";
4
4
  export { DeployTargetNotYetSupported, InvalidTargetOptions, ProviderRemoved, TargetEntryInvalid, TargetPackageInvalid, TargetPackageNotFound, TargetRuntimeMismatch, TargetRuntimeUndeclared, UnknownDeployTarget, defineTarget, isDeployTarget };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@geekmidas/cli",
3
- "version": "10.0.0-alpha.105",
3
+ "version": "10.0.0-alpha.106",
4
4
  "description": "CLI tools for building Lambda handlers, server applications, and generating OpenAPI specs",
5
5
  "private": false,
6
6
  "type": "module",
@@ -120,16 +120,16 @@
120
120
  "prompts": "~2.4.2",
121
121
  "tsx": "~4.23.15",
122
122
  "yaml": "~2.9.1",
123
- "@geekmidas/cache": "10.0.0-alpha.105",
124
- "@geekmidas/constructs": "~10.0.0-alpha.105",
125
- "@geekmidas/db": "10.0.0-alpha.105",
126
- "@geekmidas/envkit": "~10.0.0-alpha.105",
127
- "@geekmidas/errors": "~10.0.0-alpha.105",
128
- "@geekmidas/logger": "~10.0.0-alpha.105",
129
- "@geekmidas/manifest": "10.0.0-alpha.105",
130
- "@geekmidas/schema": "~10.0.0-alpha.105",
131
- "@geekmidas/services": "~10.0.0-alpha.105",
132
- "@geekmidas/storage": "~10.0.0-alpha.105"
123
+ "@geekmidas/cache": "10.0.0-alpha.106",
124
+ "@geekmidas/constructs": "~10.0.0-alpha.106",
125
+ "@geekmidas/db": "10.0.0-alpha.106",
126
+ "@geekmidas/envkit": "~10.0.0-alpha.106",
127
+ "@geekmidas/errors": "~10.0.0-alpha.106",
128
+ "@geekmidas/logger": "~10.0.0-alpha.106",
129
+ "@geekmidas/manifest": "10.0.0-alpha.106",
130
+ "@geekmidas/schema": "~10.0.0-alpha.106",
131
+ "@geekmidas/services": "~10.0.0-alpha.106",
132
+ "@geekmidas/storage": "~10.0.0-alpha.106"
133
133
  },
134
134
  "devDependencies": {
135
135
  "@hono/node-server": "~1.19.5",
@@ -144,12 +144,12 @@
144
144
  "typescript": "~7.0.2",
145
145
  "vitest": "~5.0.2",
146
146
  "zod": "~4.6.5",
147
- "@geekmidas/emailkit": "~10.0.0-alpha.105",
148
- "@geekmidas/events": "~10.0.0-alpha.105",
149
- "@geekmidas/testkit": "10.0.0-alpha.105"
147
+ "@geekmidas/emailkit": "~10.0.0-alpha.106",
148
+ "@geekmidas/events": "~10.0.0-alpha.106",
149
+ "@geekmidas/testkit": "10.0.0-alpha.106"
150
150
  },
151
151
  "peerDependencies": {
152
- "@geekmidas/telescope": "~10.0.0-alpha.105"
152
+ "@geekmidas/telescope": "~10.0.0-alpha.106"
153
153
  },
154
154
  "peerDependenciesMeta": {
155
155
  "@geekmidas/telescope": {
@@ -1 +0,0 @@
1
- {"version":3,"file":"appPorts-C9z9Pzn9.mjs","names":[],"sources":["../src/dev/appPorts.ts"],"sourcesContent":["/**\n * Which local port each app answers on — and what to do when it is taken.\n *\n * An app's port used to be fixed: 3000, 3001, … and `gkm dev` refused to start\n * if anything held one. That is right when the holder is this same app, left\n * running by a previous `gkm dev` — moving would start a second copy beside it.\n * It is wrong when the holder is another project's dev server, which also\n * defaults to 3000: two projects could not run at once, and nothing about the\n * app needs that port. A browser reaches it through the edge, whose URL carries\n * no app port, and every address a phone or a route uses is derived on each\n * start.\n *\n * So the holder is asked who it is. Every app process gkm starts is tagged with\n * {@link APP_TAG_ENV} — the workspace and the app — and children inherit it, so\n * whatever actually binds the port (`next-server`, a Metro worker, the tsx\n * server) carries it — or, when its own can't be read, one of its parents does.\n * A held port whose holder carries this app's tag is a\n * leftover, and is refused; anything else — untagged, another workspace's,\n * unreadable — is not ours, and the app moves to the next free port.\n *\n * The choice is kept in `.gkm/app-ports.json`, not recomputed: an app that\n * moved stays where it moved, so a bookmark or a phone's saved address does not\n * break the next time the other project happens to be stopped. Local only —\n * `gkm deploy` and `gkm docker` never read it.\n */\n\nimport { execFileSync } from 'node:child_process';\nimport { readFileSync } from 'node:fs';\nimport { mkdir, readFile, writeFile } from 'node:fs/promises';\nimport { join, resolve } from 'node:path';\nimport type { NormalizedWorkspace } from '../workspace/types.js';\n\n/** Carried by every app process gkm starts: `<workspace root>#<app>`. */\nexport const APP_TAG_ENV = 'GKM_DEV_APP';\n\nconst APP_PORTS_PATH = '.gkm/app-ports.json';\n\n/** The tag an app's processes carry. The root is encoded, so it has no spaces. */\nexport function appTag(root: string, app: string): string {\n\treturn `${encodeURIComponent(resolve(root))}#${app}`;\n}\n\n/** What listens on a port, and the tag it carries if it can be read. */\nexport interface PortHolder {\n\tpid: number;\n\tcommand?: string;\n\ttag?: string;\n}\n\n/** Says, as `command (pid N)`, what holds a port. */\nexport function describeHolder(holder: PortHolder | undefined): string {\n\tif (!holder) return 'another process';\n\treturn `${holder.command ?? 'a process'} (pid ${holder.pid})`;\n}\n\n/**\n * Who is listening on a port, read the way a person would: `lsof` for the\n * pid, then that process's environment for its tag — `/proc/<pid>/environ` on\n * Linux, `ps eww` elsewhere. Both work for the user's own processes, which is\n * every process gkm starts; one that cannot be read has no tag, so is not ours.\n */\nexport function holderOf(port: number): PortHolder | undefined {\n\tlet out: string;\n\ttry {\n\t\tout = execFileSync(\n\t\t\t'lsof',\n\t\t\t['-nP', `-iTCP:${port}`, '-sTCP:LISTEN', '-Fpc'],\n\t\t\t{ encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] },\n\t\t);\n\t} catch {\n\t\treturn undefined;\n\t}\n\n\tconst pid = Number(out.match(/^p(\\d+)/m)?.[1]);\n\tif (!pid) return undefined;\n\tconst command = out.match(/^c(.+)$/m)?.[1];\n\tconst tag = lineageTagOf(pid);\n\n\treturn {\n\t\tpid,\n\t\t...(command ? { command } : {}),\n\t\t...(tag ? { tag } : {}),\n\t};\n}\n\n/** How far up a holder's parents to look before calling it untagged. */\nconst MAX_ANCESTORS = 8;\n\n/**\n * The tag of `pid`, or of its nearest parent that has one.\n *\n * A process can hide the tag it inherited: `next-server` renames itself, which\n * on macOS overwrites the memory `ps eww` reads its environment from, so `ps`\n * shows only its title. Its parent, the `next dev` gkm started, still carries\n * the tag. A child is only ever started by its parent, so a tagged parent makes\n * the holder this app's.\n */\nfunction lineageTagOf(pid: number): string | undefined {\n\tlet current: number | undefined = pid;\n\tfor (let depth = 0; current && current > 1; depth += 1) {\n\t\tconst tag = tagOf(current);\n\t\tif (tag || depth === MAX_ANCESTORS) return tag;\n\t\tcurrent = parentOf(current);\n\t}\n\treturn undefined;\n}\n\nfunction tagOf(pid: number): string | undefined {\n\tconst prefix = `${APP_TAG_ENV}=`;\n\ttry {\n\t\tconst entries =\n\t\t\tprocess.platform === 'linux'\n\t\t\t\t? readFileSync(`/proc/${pid}/environ`, 'utf8').split('\\0')\n\t\t\t\t: execFileSync('ps', ['eww', '-o', 'command=', '-p', String(pid)], {\n\t\t\t\t\t\tencoding: 'utf8',\n\t\t\t\t\t\tstdio: ['ignore', 'pipe', 'ignore'],\n\t\t\t\t\t}).split(/\\s+/);\n\t\treturn entries\n\t\t\t.find((entry) => entry.startsWith(prefix))\n\t\t\t?.slice(prefix.length);\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\nfunction parentOf(pid: number): number | undefined {\n\ttry {\n\t\tconst ppid = Number(\n\t\t\texecFileSync('ps', ['-o', 'ppid=', '-p', String(pid)], {\n\t\t\t\tencoding: 'utf8',\n\t\t\t\tstdio: ['ignore', 'pipe', 'ignore'],\n\t\t\t}).trim(),\n\t\t);\n\t\treturn ppid > 0 ? ppid : undefined;\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\n/** The ports apps were given before, by app name. */\nexport async function savedAppPorts(\n\troot: string,\n): Promise<Record<string, number>> {\n\ttry {\n\t\treturn JSON.parse(await readFile(join(root, APP_PORTS_PATH), 'utf8'));\n\t} catch {\n\t\treturn {};\n\t}\n}\n\nasync function saveAppPorts(\n\troot: string,\n\tports: Record<string, number>,\n): Promise<void> {\n\tawait mkdir(join(root, '.gkm'), { recursive: true });\n\tawait writeFile(\n\t\tjoin(root, APP_PORTS_PATH),\n\t\t`${JSON.stringify(ports, null, 2)}\\n`,\n\t);\n}\n\n/** The workspace, with each app on the port it was given locally. */\nexport function withAppPorts(\n\tworkspace: NormalizedWorkspace,\n\tports: Readonly<Record<string, number>>,\n): NormalizedWorkspace {\n\tconst apps = Object.fromEntries(\n\t\tObject.entries(workspace.apps).map(([name, app]) => [\n\t\t\tname,\n\t\t\tports[name] ? { ...app, port: ports[name] } : app,\n\t\t]),\n\t);\n\treturn { ...workspace, apps };\n}\n\n/** An app this workspace already has running — left by a previous start. */\nexport interface AppRunning {\n\tapp: string;\n\tport: number;\n\tholder: PortHolder;\n}\n\n/** An app that moved, because another project holds its port. */\nexport interface AppMoved {\n\tapp: string;\n\tfrom: number;\n\tto: number;\n\tholder: PortHolder | undefined;\n}\n\nexport interface AppPortsDeps {\n\t/** Whether a port can be bound right now. */\n\tfree: (port: number) => Promise<boolean>;\n\t/** Who holds a port. */\n\tholder: (port: number) => PortHolder | undefined;\n}\n\n/**\n * Give each named app a local port: the one it had, or its usual one, unless\n * another project holds it — then the next free one, which is kept.\n *\n * @returns every app's port, the apps that moved, and the apps this workspace\n * already has running (the caller refuses to start those).\n */\nexport async function assignAppPorts(\n\tworkspace: NormalizedWorkspace,\n\tnames: readonly string[],\n\tdeps: AppPortsDeps,\n): Promise<{\n\tports: Record<string, number>;\n\tmoved: AppMoved[];\n\trunning: AppRunning[];\n}> {\n\tconst saved = await savedAppPorts(workspace.root);\n\tconst wanted: Record<string, number> = {};\n\tfor (const name of names) {\n\t\tconst port = saved[name] ?? workspace.apps[name]?.port;\n\t\tif (port) wanted[name] = port;\n\t}\n\n\t// Every app's wanted port is reserved before any moves, so one that moves\n\t// never lands on a sibling's.\n\tconst taken = new Set([...Object.values(saved), ...Object.values(wanted)]);\n\tconst ports: Record<string, number> = { ...saved };\n\tconst moved: AppMoved[] = [];\n\tconst running: AppRunning[] = [];\n\n\t// Sorted, so which app moves first — and where — does not depend on order.\n\tfor (const name of Object.keys(wanted).sort()) {\n\t\tconst want = wanted[name]!;\n\t\tports[name] = want;\n\t\tif (await deps.free(want)) continue;\n\n\t\tconst holder = deps.holder(want);\n\t\tif (holder?.tag === appTag(workspace.root, name)) {\n\t\t\trunning.push({ app: name, port: want, holder });\n\t\t\tcontinue;\n\t\t}\n\n\t\tlet next = want + 1;\n\t\twhile (taken.has(next) || !(await deps.free(next))) next += 1;\n\t\ttaken.add(next);\n\t\tports[name] = next;\n\t\tmoved.push({ app: name, from: want, to: next, holder });\n\t}\n\n\tawait saveAppPorts(workspace.root, ports);\n\treturn { ports, moved, running };\n}\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"appPorts-Cu79hJF6.cjs","names":["resolve","execFileSync","readFileSync","readFile","join","mkdir","writeFile"],"sources":["../src/dev/appPorts.ts"],"sourcesContent":["/**\n * Which local port each app answers on — and what to do when it is taken.\n *\n * An app's port used to be fixed: 3000, 3001, … and `gkm dev` refused to start\n * if anything held one. That is right when the holder is this same app, left\n * running by a previous `gkm dev` — moving would start a second copy beside it.\n * It is wrong when the holder is another project's dev server, which also\n * defaults to 3000: two projects could not run at once, and nothing about the\n * app needs that port. A browser reaches it through the edge, whose URL carries\n * no app port, and every address a phone or a route uses is derived on each\n * start.\n *\n * So the holder is asked who it is. Every app process gkm starts is tagged with\n * {@link APP_TAG_ENV} — the workspace and the app — and children inherit it, so\n * whatever actually binds the port (`next-server`, a Metro worker, the tsx\n * server) carries it — or, when its own can't be read, one of its parents does.\n * A held port whose holder carries this app's tag is a\n * leftover, and is refused; anything else — untagged, another workspace's,\n * unreadable — is not ours, and the app moves to the next free port.\n *\n * The choice is kept in `.gkm/app-ports.json`, not recomputed: an app that\n * moved stays where it moved, so a bookmark or a phone's saved address does not\n * break the next time the other project happens to be stopped. Local only —\n * `gkm deploy` and `gkm docker` never read it.\n */\n\nimport { execFileSync } from 'node:child_process';\nimport { readFileSync } from 'node:fs';\nimport { mkdir, readFile, writeFile } from 'node:fs/promises';\nimport { join, resolve } from 'node:path';\nimport type { NormalizedWorkspace } from '../workspace/types.js';\n\n/** Carried by every app process gkm starts: `<workspace root>#<app>`. */\nexport const APP_TAG_ENV = 'GKM_DEV_APP';\n\nconst APP_PORTS_PATH = '.gkm/app-ports.json';\n\n/** The tag an app's processes carry. The root is encoded, so it has no spaces. */\nexport function appTag(root: string, app: string): string {\n\treturn `${encodeURIComponent(resolve(root))}#${app}`;\n}\n\n/** What listens on a port, and the tag it carries if it can be read. */\nexport interface PortHolder {\n\tpid: number;\n\tcommand?: string;\n\ttag?: string;\n}\n\n/** Says, as `command (pid N)`, what holds a port. */\nexport function describeHolder(holder: PortHolder | undefined): string {\n\tif (!holder) return 'another process';\n\treturn `${holder.command ?? 'a process'} (pid ${holder.pid})`;\n}\n\n/**\n * Who is listening on a port, read the way a person would: `lsof` for the\n * pid, then that process's environment for its tag — `/proc/<pid>/environ` on\n * Linux, `ps eww` elsewhere. Both work for the user's own processes, which is\n * every process gkm starts; one that cannot be read has no tag, so is not ours.\n */\nexport function holderOf(port: number): PortHolder | undefined {\n\tlet out: string;\n\ttry {\n\t\tout = execFileSync(\n\t\t\t'lsof',\n\t\t\t['-nP', `-iTCP:${port}`, '-sTCP:LISTEN', '-Fpc'],\n\t\t\t{ encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] },\n\t\t);\n\t} catch {\n\t\treturn undefined;\n\t}\n\n\tconst pid = Number(out.match(/^p(\\d+)/m)?.[1]);\n\tif (!pid) return undefined;\n\tconst command = out.match(/^c(.+)$/m)?.[1];\n\tconst tag = lineageTagOf(pid);\n\n\treturn {\n\t\tpid,\n\t\t...(command ? { command } : {}),\n\t\t...(tag ? { tag } : {}),\n\t};\n}\n\n/** How far up a holder's parents to look before calling it untagged. */\nconst MAX_ANCESTORS = 8;\n\n/**\n * The tag of `pid`, or of its nearest parent that has one.\n *\n * A process can hide the tag it inherited: `next-server` renames itself, which\n * on macOS overwrites the memory `ps eww` reads its environment from, so `ps`\n * shows only its title. Its parent, the `next dev` gkm started, still carries\n * the tag. A child is only ever started by its parent, so a tagged parent makes\n * the holder this app's.\n */\nfunction lineageTagOf(pid: number): string | undefined {\n\tlet current: number | undefined = pid;\n\tfor (let depth = 0; current && current > 1; depth += 1) {\n\t\tconst tag = tagOf(current);\n\t\tif (tag || depth === MAX_ANCESTORS) return tag;\n\t\tcurrent = parentOf(current);\n\t}\n\treturn undefined;\n}\n\nfunction tagOf(pid: number): string | undefined {\n\tconst prefix = `${APP_TAG_ENV}=`;\n\ttry {\n\t\tconst entries =\n\t\t\tprocess.platform === 'linux'\n\t\t\t\t? readFileSync(`/proc/${pid}/environ`, 'utf8').split('\\0')\n\t\t\t\t: execFileSync('ps', ['eww', '-o', 'command=', '-p', String(pid)], {\n\t\t\t\t\t\tencoding: 'utf8',\n\t\t\t\t\t\tstdio: ['ignore', 'pipe', 'ignore'],\n\t\t\t\t\t}).split(/\\s+/);\n\t\treturn entries\n\t\t\t.find((entry) => entry.startsWith(prefix))\n\t\t\t?.slice(prefix.length);\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\nfunction parentOf(pid: number): number | undefined {\n\ttry {\n\t\tconst ppid = Number(\n\t\t\texecFileSync('ps', ['-o', 'ppid=', '-p', String(pid)], {\n\t\t\t\tencoding: 'utf8',\n\t\t\t\tstdio: ['ignore', 'pipe', 'ignore'],\n\t\t\t}).trim(),\n\t\t);\n\t\treturn ppid > 0 ? ppid : undefined;\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\n/** The ports apps were given before, by app name. */\nexport async function savedAppPorts(\n\troot: string,\n): Promise<Record<string, number>> {\n\ttry {\n\t\treturn JSON.parse(await readFile(join(root, APP_PORTS_PATH), 'utf8'));\n\t} catch {\n\t\treturn {};\n\t}\n}\n\nasync function saveAppPorts(\n\troot: string,\n\tports: Record<string, number>,\n): Promise<void> {\n\tawait mkdir(join(root, '.gkm'), { recursive: true });\n\tawait writeFile(\n\t\tjoin(root, APP_PORTS_PATH),\n\t\t`${JSON.stringify(ports, null, 2)}\\n`,\n\t);\n}\n\n/** The workspace, with each app on the port it was given locally. */\nexport function withAppPorts(\n\tworkspace: NormalizedWorkspace,\n\tports: Readonly<Record<string, number>>,\n): NormalizedWorkspace {\n\tconst apps = Object.fromEntries(\n\t\tObject.entries(workspace.apps).map(([name, app]) => [\n\t\t\tname,\n\t\t\tports[name] ? { ...app, port: ports[name] } : app,\n\t\t]),\n\t);\n\treturn { ...workspace, apps };\n}\n\n/** An app this workspace already has running — left by a previous start. */\nexport interface AppRunning {\n\tapp: string;\n\tport: number;\n\tholder: PortHolder;\n}\n\n/** An app that moved, because another project holds its port. */\nexport interface AppMoved {\n\tapp: string;\n\tfrom: number;\n\tto: number;\n\tholder: PortHolder | undefined;\n}\n\nexport interface AppPortsDeps {\n\t/** Whether a port can be bound right now. */\n\tfree: (port: number) => Promise<boolean>;\n\t/** Who holds a port. */\n\tholder: (port: number) => PortHolder | undefined;\n}\n\n/**\n * Give each named app a local port: the one it had, or its usual one, unless\n * another project holds it — then the next free one, which is kept.\n *\n * @returns every app's port, the apps that moved, and the apps this workspace\n * already has running (the caller refuses to start those).\n */\nexport async function assignAppPorts(\n\tworkspace: NormalizedWorkspace,\n\tnames: readonly string[],\n\tdeps: AppPortsDeps,\n): Promise<{\n\tports: Record<string, number>;\n\tmoved: AppMoved[];\n\trunning: AppRunning[];\n}> {\n\tconst saved = await savedAppPorts(workspace.root);\n\tconst wanted: Record<string, number> = {};\n\tfor (const name of names) {\n\t\tconst port = saved[name] ?? workspace.apps[name]?.port;\n\t\tif (port) wanted[name] = port;\n\t}\n\n\t// Every app's wanted port is reserved before any moves, so one that moves\n\t// never lands on a sibling's.\n\tconst taken = new Set([...Object.values(saved), ...Object.values(wanted)]);\n\tconst ports: Record<string, number> = { ...saved };\n\tconst moved: AppMoved[] = [];\n\tconst running: AppRunning[] = [];\n\n\t// Sorted, so which app moves first — and where — does not depend on order.\n\tfor (const name of Object.keys(wanted).sort()) {\n\t\tconst want = wanted[name]!;\n\t\tports[name] = want;\n\t\tif (await deps.free(want)) continue;\n\n\t\tconst holder = deps.holder(want);\n\t\tif (holder?.tag === appTag(workspace.root, name)) {\n\t\t\trunning.push({ app: name, port: want, holder });\n\t\t\tcontinue;\n\t\t}\n\n\t\tlet next = want + 1;\n\t\twhile (taken.has(next) || !(await deps.free(next))) next += 1;\n\t\ttaken.add(next);\n\t\tports[name] = next;\n\t\tmoved.push({ app: name, from: want, to: next, holder });\n\t}\n\n\tawait saveAppPorts(workspace.root, ports);\n\treturn { ports, moved, running };\n}\n"],"mappings":"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"}