@astra-kit/rp 0.0.0-stage → 0.10.0

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 (125) hide show
  1. package/CHANGELOG.md +196 -0
  2. package/LICENSE.md +21 -0
  3. package/README.md +352 -2
  4. package/bin/astra-rp.js +51 -0
  5. package/package.json +93 -4
  6. package/src/build-gate.js +157 -0
  7. package/src/changelog-blocks.js +53 -0
  8. package/src/changelog.js +108 -0
  9. package/src/constants/build-gate.js +30 -0
  10. package/src/constants/changelog-draft.js +180 -0
  11. package/src/constants/changelog.js +74 -0
  12. package/src/constants/ci-release.js +346 -0
  13. package/src/constants/cli.js +12 -0
  14. package/src/constants/create-version.js +523 -0
  15. package/src/constants/guard-publish.js +29 -0
  16. package/src/constants/index.js +18 -0
  17. package/src/constants/monorepo.js +57 -0
  18. package/src/constants/package-manager.js +56 -0
  19. package/src/constants/registry.js +72 -0
  20. package/src/constants/terminal-ui.js +93 -0
  21. package/src/constants/version-files.js +63 -0
  22. package/src/constants/versions.js +60 -0
  23. package/src/create-version/artifact.js +343 -0
  24. package/src/create-version/changelog-draft-workspace.js +124 -0
  25. package/src/create-version/changelog-draft.js +380 -0
  26. package/src/create-version/changelog.js +264 -0
  27. package/src/create-version/ci-config.js +54 -0
  28. package/src/create-version/ci-publication-history.js +113 -0
  29. package/src/create-version/ci-release-identity-step.js +58 -0
  30. package/src/create-version/ci-setup.js +794 -0
  31. package/src/create-version/ci.js +555 -0
  32. package/src/create-version/committed-tree.js +75 -0
  33. package/src/create-version/config.js +489 -0
  34. package/src/create-version/errors.js +46 -0
  35. package/src/create-version/github-workflow.js +199 -0
  36. package/src/create-version/index.js +54 -0
  37. package/src/create-version/json.js +32 -0
  38. package/src/create-version/jsonc.js +76 -0
  39. package/src/create-version/jsr.js +96 -0
  40. package/src/create-version/local-changes.js +178 -0
  41. package/src/create-version/npm-auth.js +142 -0
  42. package/src/create-version/npm.js +812 -0
  43. package/src/create-version/plan.js +1200 -0
  44. package/src/create-version/process.js +334 -0
  45. package/src/create-version/registry-config.js +121 -0
  46. package/src/create-version/registry-http.js +62 -0
  47. package/src/create-version/registry.js +220 -0
  48. package/src/create-version/release-execution.js +45 -0
  49. package/src/create-version/release-tag-config.js +76 -0
  50. package/src/create-version/run.js +2087 -0
  51. package/src/create-version/state.js +461 -0
  52. package/src/create-version/strict-utf8.js +11 -0
  53. package/src/create-version/templates/release.yml +52 -0
  54. package/src/create-version/templates/vercel-ignore-build.mjs +66 -0
  55. package/src/guard-publish.js +77 -0
  56. package/src/index.js +42 -0
  57. package/src/monorepo/plan.js +475 -0
  58. package/src/monorepo/release-commit.js +46 -0
  59. package/src/monorepo/run.js +927 -0
  60. package/src/monorepo/state.js +206 -0
  61. package/src/monorepo/workspaces.js +327 -0
  62. package/src/package-manager.js +107 -0
  63. package/src/terminal-ui.js +548 -0
  64. package/src/testing.js +70 -0
  65. package/src/version-files.js +142 -0
  66. package/src/versions.js +303 -0
  67. package/types/build-gate.d.ts +43 -0
  68. package/types/changelog-blocks.d.ts +33 -0
  69. package/types/changelog.d.ts +61 -0
  70. package/types/constants/build-gate.d.ts +23 -0
  71. package/types/constants/changelog-draft.d.ts +138 -0
  72. package/types/constants/changelog.d.ts +56 -0
  73. package/types/constants/ci-release.d.ts +284 -0
  74. package/types/constants/cli.d.ts +11 -0
  75. package/types/constants/create-version.d.ts +397 -0
  76. package/types/constants/guard-publish.d.ts +25 -0
  77. package/types/constants/index.d.ts +17 -0
  78. package/types/constants/monorepo.d.ts +45 -0
  79. package/types/constants/package-manager.d.ts +40 -0
  80. package/types/constants/registry.d.ts +79 -0
  81. package/types/constants/terminal-ui.d.ts +73 -0
  82. package/types/constants/version-files.d.ts +51 -0
  83. package/types/constants/versions.d.ts +47 -0
  84. package/types/create-version/artifact.d.ts +113 -0
  85. package/types/create-version/changelog-draft-workspace.d.ts +33 -0
  86. package/types/create-version/changelog-draft.d.ts +127 -0
  87. package/types/create-version/changelog.d.ts +141 -0
  88. package/types/create-version/ci-config.d.ts +33 -0
  89. package/types/create-version/ci-publication-history.d.ts +51 -0
  90. package/types/create-version/ci-release-identity-step.d.ts +12 -0
  91. package/types/create-version/ci-setup.d.ts +148 -0
  92. package/types/create-version/ci.d.ts +145 -0
  93. package/types/create-version/committed-tree.d.ts +55 -0
  94. package/types/create-version/config.d.ts +128 -0
  95. package/types/create-version/errors.d.ts +39 -0
  96. package/types/create-version/github-workflow.d.ts +41 -0
  97. package/types/create-version/index.d.ts +28 -0
  98. package/types/create-version/json.d.ts +21 -0
  99. package/types/create-version/jsonc.d.ts +21 -0
  100. package/types/create-version/jsr.d.ts +52 -0
  101. package/types/create-version/local-changes.d.ts +52 -0
  102. package/types/create-version/npm-auth.d.ts +60 -0
  103. package/types/create-version/npm.d.ts +331 -0
  104. package/types/create-version/plan.d.ts +369 -0
  105. package/types/create-version/process.d.ts +151 -0
  106. package/types/create-version/registry-config.d.ts +56 -0
  107. package/types/create-version/registry-http.d.ts +22 -0
  108. package/types/create-version/registry.d.ts +86 -0
  109. package/types/create-version/release-execution.d.ts +22 -0
  110. package/types/create-version/release-tag-config.d.ts +18 -0
  111. package/types/create-version/run.d.ts +407 -0
  112. package/types/create-version/state.d.ts +204 -0
  113. package/types/create-version/strict-utf8.d.ts +10 -0
  114. package/types/guard-publish.d.ts +49 -0
  115. package/types/index.d.ts +23 -0
  116. package/types/monorepo/plan.d.ts +68 -0
  117. package/types/monorepo/release-commit.d.ts +29 -0
  118. package/types/monorepo/run.d.ts +68 -0
  119. package/types/monorepo/state.d.ts +96 -0
  120. package/types/monorepo/workspaces.d.ts +86 -0
  121. package/types/package-manager.d.ts +58 -0
  122. package/types/terminal-ui.d.ts +196 -0
  123. package/types/testing.d.ts +31 -0
  124. package/types/version-files.d.ts +59 -0
  125. package/types/versions.d.ts +158 -0
@@ -0,0 +1,523 @@
1
+ /**
2
+ * Git, npm, configuration and display values of the shared `astra-rp create-version` command.
3
+ *
4
+ * @module constants/create-version
5
+ */
6
+
7
+ import { GITHUB_REGISTRY_PROVIDER, GITLAB_REGISTRY_PROVIDER, JSR_REGISTRY_PROVIDER, NPM_REGISTRY_PROVIDER, NPM_REGISTRY_TOKEN_VARIABLE } from "./registry.js";
8
+
9
+ import { DEFAULT_CREATE_VERSION_COMMAND } from "./package-manager.js";
10
+ import { COMMIT_SHORT_SHA_LENGTH } from "./changelog.js";
11
+
12
+ /** Branch that receives releases. */
13
+ export const MAIN_BRANCH = "main";
14
+
15
+ /** Remote that receives releases. */
16
+ export const RELEASE_REMOTE = "origin";
17
+
18
+ /** Remote-tracking ref of the release branch. */
19
+ export const REMOTE_MAIN_REF = `${RELEASE_REMOTE}/${MAIN_BRANCH}`;
20
+
21
+ /** Configuration module read from the repository root. */
22
+ export const CREATE_VERSION_CONFIG_FILE = "astra-rp.config.js";
23
+
24
+ /**
25
+ * Configuration candidates in lookup order: `.mjs` is always ESM, so projects
26
+ * without `"type": "module"` load it without Node warnings.
27
+ */
28
+ export const CREATE_VERSION_CONFIG_FILES = Object.freeze(["astra-rp.config.mjs", CREATE_VERSION_CONFIG_FILE]);
29
+
30
+ /** Manifest whose `version` is released; shared with the build gate. */
31
+ export { PACKAGE_MANIFEST_FILE } from "./build-gate.js";
32
+
33
+ /** Pinned Node.js version compared with the running one when present; a full version or only its major. */
34
+ export const PINNED_NODE_VERSION_FILE = ".nvmrc";
35
+
36
+ /** Environment file that may hold `NPM_TOKEN` locally; ignored by Git. */
37
+ export const LOCAL_ENVIRONMENT_FILE = ".env";
38
+
39
+ /** Environment variable that holds the npm token; the temporary npm config references it as `${NPM_TOKEN}`. */
40
+ export const NPM_TOKEN_VARIABLE = NPM_REGISTRY_TOKEN_VARIABLE;
41
+
42
+ /**
43
+ * Path segments, relative to the user home directory (`os.homedir()`), of the environment file
44
+ * shared by every project: one `NPM_TOKEN` for all the repositories that release with astra-rp.
45
+ */
46
+ export const SHARED_ENVIRONMENT_FILE_SEGMENTS = Object.freeze([".config", "astra-rp", LOCAL_ENVIRONMENT_FILE]);
47
+
48
+ /** How the shared environment file is shown to the user, independent of the platform. */
49
+ export const SHARED_ENVIRONMENT_FILE_LABEL = `~/${SHARED_ENVIRONMENT_FILE_SEGMENTS.join("/")}`;
50
+
51
+ /** Where `NPM_TOKEN` was found, in lookup order: environment, repository `.env`, shared file. */
52
+ export const NPM_TOKEN_SOURCE = Object.freeze({
53
+ environment: "environment",
54
+ repository: "repository",
55
+ shared: "shared",
56
+ });
57
+
58
+ /** How each {@link NPM_TOKEN_SOURCE} is named in the diagnosis and the error messages; never the token. */
59
+ export const NPM_TOKEN_SOURCE_LABEL = Object.freeze({
60
+ [NPM_TOKEN_SOURCE.environment]: "variable de entorno",
61
+ [NPM_TOKEN_SOURCE.repository]: `${LOCAL_ENVIRONMENT_FILE} del repo`,
62
+ [NPM_TOKEN_SOURCE.shared]: SHARED_ENVIRONMENT_FILE_LABEL,
63
+ });
64
+
65
+ /**
66
+ * Result of checking the npm credentials before publishing:
67
+ * - `ok`: the token authenticates and its user owns the package (or it was never published); npm
68
+ * cannot tell beforehand whether the token itself can write (read-only or granular tokens);
69
+ * - `missingToken`: no source defines `NPM_TOKEN`;
70
+ * - `invalidToken`: the registry rejects the token (`npm whoami` answers 401/403);
71
+ * - `notOwner`: the token authenticates as a user that is not an owner of the package;
72
+ * - `projectCredentials`: the project `.npmrc` defines credentials for the publish registry, which
73
+ * npm prefers over the temporary config that binds `NPM_TOKEN`;
74
+ * - `unknown`: the check could not finish (network, a registry without `npm owner ls`, an
75
+ * organization package whose access may come from a team); it warns but does not block.
76
+ */
77
+ export const NPM_AUTH_STATUS = Object.freeze({
78
+ ok: "ok",
79
+ missingToken: "missing-token",
80
+ invalidToken: "invalid-token",
81
+ notOwner: "not-owner",
82
+ projectCredentials: "project-credentials",
83
+ unsupportedAuth: "unsupported-auth",
84
+ unknown: "unknown",
85
+ });
86
+
87
+ /** npm error codes of a rejected credential: `npm whoami` fails with them for an invalid or expired token. */
88
+ export const NPM_REJECTED_CREDENTIAL_PATTERN = /\bE40[13]\b/u;
89
+
90
+ /** Where `NPM_TOKEN` can be defined, in lookup order, as the credential messages explain it. */
91
+ export const NPM_TOKEN_LOCATIONS = `la variable de entorno ${NPM_TOKEN_VARIABLE}, el ${LOCAL_ENVIRONMENT_FILE} del repo (ignorado por Git) o ${SHARED_ENVIRONMENT_FILE_LABEL} (un solo token para todos tus proyectos)`;
92
+
93
+ /** Why npm answers 404 to a publication the token cannot make. */
94
+ export const NPM_PUT_NOT_FOUND_NOTE = "Un 404 Not Found de npm en el PUT suele significar falta de permisos sobre el paquete (npm responde 404 en vez de 403).";
95
+
96
+ /** Diagnosis note of an owner token: npm exposes no side-effect-free way to check its write permission. */
97
+ export const NPM_WRITE_ACCESS_UNVERIFIED_NOTE = "permiso de escritura del token no verificable antes de publicar";
98
+
99
+ /** Why a failed publication can still be the token when its user owns the package. */
100
+ export const NPM_READ_ONLY_TOKEN_NOTE =
101
+ "El token puede ser read-only o granular sin permiso de escritura sobre el paquete (npm no permite verificarlo antes de publicar): revisalo en npm → Access Tokens.";
102
+
103
+ /**
104
+ * Next action after fixing the npm credentials reported by the diagnosis.
105
+ *
106
+ * @param {string} createVersionCommand - How the project runs create-version (`pnpm create-version`, `bun run create-version`…).
107
+ * @returns {string} Spanish next action.
108
+ */
109
+ export const buildNpmAuthRerunAction = (createVersionCommand) => `volvé a correr ${createVersionCommand}`;
110
+
111
+ /**
112
+ * Next action after fixing the npm credentials once `npm publish` failed.
113
+ *
114
+ * @param {string} createVersionCommand - How the project runs create-version.
115
+ * @returns {string} Spanish next action.
116
+ */
117
+ export const buildNpmPublishRetryAction = (createVersionCommand) => `corré ${createVersionCommand} para reintentar solo la publicación`;
118
+
119
+ /** {@link buildNpmAuthRerunAction} of a pnpm project. */
120
+ export const NPM_AUTH_RERUN_ACTION = buildNpmAuthRerunAction(DEFAULT_CREATE_VERSION_COMMAND);
121
+
122
+ /** {@link buildNpmPublishRetryAction} of a pnpm project. */
123
+ export const NPM_PUBLISH_RETRY_ACTION = buildNpmPublishRetryAction(DEFAULT_CREATE_VERSION_COMMAND);
124
+
125
+ /**
126
+ * Option that keeps the plain text output of `npm whoami` and `npm owner ls` even when the project
127
+ * config or the environment enables npm's global JSON output (`json=true`, `npm_config_json=true`).
128
+ */
129
+ export const NPM_PLAIN_OUTPUT_OPTION = "--json=false";
130
+
131
+ /** Arguments of the npm command that prints the user a token authenticates as. */
132
+ export const NPM_WHOAMI_ARGUMENTS = Object.freeze(["whoami", NPM_PLAIN_OUTPUT_OPTION]);
133
+
134
+ /** Arguments of the npm command that lists the owners of a package, followed by the package name. */
135
+ export const NPM_OWNER_LIST_ARGUMENTS = Object.freeze(["owner", "ls", NPM_PLAIN_OUTPUT_OPTION]);
136
+
137
+ /** Project npm config, read from the repository root; npm prefers it over the temporary `--userconfig`. */
138
+ export const PROJECT_NPM_CONFIG_FILE = ".npmrc";
139
+
140
+ /**
141
+ * npm config fields that select the HTTP credential of a registry, either bound to it
142
+ * (`//host/path/:_authToken`) or unbound (`_authToken`); any of them in the project `.npmrc` or in an
143
+ * inherited `npm_config_*` variable overrides `NPM_TOKEN`. TLS client options such as `keyfile` or
144
+ * `certfile` are not listed: they do not replace the token.
145
+ */
146
+ export const NPM_CREDENTIAL_CONFIG_FIELDS = Object.freeze(["_authToken", "_auth", "_password", "username"]);
147
+
148
+ /** Prefix of the environment variables npm reads as config, in any casing (`npm_config_`, `NPM_CONFIG_`). */
149
+ export const NPM_CONFIG_ENVIRONMENT_PREFIX = "npm_config_";
150
+
151
+ /** Prefix of an npm config key bound to a registry: `//host[:port]/path/:field`. */
152
+ export const NPM_REGISTRY_BOUND_KEY_PREFIX = "//";
153
+
154
+ /** One line of `npm owner ls`: `<user> <<email>>`; the `user` group keeps the npm user name. */
155
+ export const NPM_OWNER_LINE_PATTERN = /^(?<user>[^\s<]+)(?:\s+<[^>]*>)?$/u;
156
+
157
+ /** Stable identifiers of every step the command knows how to run, in execution order. */
158
+ export const RELEASE_STEP = Object.freeze({
159
+ syncMain: "sync-main",
160
+ applyMigrations: "apply-migrations",
161
+ verifyChangelog: "verify-changelog",
162
+ runChecks: "run-checks",
163
+ bumpVersion: "bump-version",
164
+ prepareRelease: "prepare-release",
165
+ pushRelease: "push-release",
166
+ pushReleaseTag: "push-release-tag",
167
+ publishRelease: "publish-release",
168
+ });
169
+
170
+ /** What the command does with the current state. */
171
+ export const RELEASE_MODE = Object.freeze({
172
+ newRelease: "new-release",
173
+ resume: "resume",
174
+ upToDate: "up-to-date",
175
+ blocked: "blocked",
176
+ });
177
+
178
+ /** Result of a project migrations adapter. */
179
+ export const MIGRATION_STATUS = Object.freeze({
180
+ upToDate: "up-to-date",
181
+ pending: "pending",
182
+ unknown: "unknown",
183
+ });
184
+
185
+ /** Pull request states reported by `gh pr view --json state`. */
186
+ export const PULL_REQUEST_STATE = Object.freeze({
187
+ open: "OPEN",
188
+ merged: "MERGED",
189
+ closed: "CLOSED",
190
+ });
191
+
192
+ /** Fields requested from `gh pr view`. */
193
+ export const PULL_REQUEST_JSON_FIELDS = "number,url,title,state,isDraft,headRefOid";
194
+
195
+ /** Message `gh pr view` prints when the branch has no pull request. */
196
+ export const NO_PULL_REQUEST_MESSAGE_PATTERN = /no pull requests found/iu;
197
+
198
+ /** Registries whose published versions drive resumes and the banner. */
199
+ export const RELEASE_REGISTRY = Object.freeze({
200
+ npm: NPM_REGISTRY_PROVIDER,
201
+ github: GITHUB_REGISTRY_PROVIDER,
202
+ gitlab: GITLAB_REGISTRY_PROVIDER,
203
+ jsr: JSR_REGISTRY_PROVIDER,
204
+ });
205
+
206
+ /** `package.json` script run as the release checks when the configuration does not set `checks`. */
207
+ export const DEFAULT_CHECKS_SCRIPT = "ci";
208
+
209
+ /** Command line of the default release checks in a pnpm project (other package managers run `<pm> run ci`). */
210
+ export const DEFAULT_CHECKS_COMMAND = `pnpm run ${DEFAULT_CHECKS_SCRIPT}`;
211
+
212
+ /** Built-in publisher selected with `publish: "npm"`. */
213
+ export const NPM_PUBLISHER = NPM_REGISTRY_PROVIDER;
214
+
215
+ /** Result of asking npm which versions of the package exist. */
216
+ export const NPM_LOOKUP_STATUS = Object.freeze({
217
+ ok: "ok",
218
+ failed: "failed",
219
+ });
220
+
221
+ /** Valid npm package name (optionally scoped), checked before it reaches a shell command line. */
222
+ export const NPM_PACKAGE_NAME_PATTERN = /^(?:@[a-z0-9-~][a-z0-9-._~]*\/)?[a-z0-9-~][a-z0-9-._~]*$/u;
223
+
224
+ /** npm error code of a package that was never published. */
225
+ export const NPM_NOT_FOUND_CODE = "E404";
226
+
227
+ /** npm dist-tag every stable release is published under. */
228
+ export const NPM_DIST_TAG = "latest";
229
+
230
+
231
+ /** Command-line flags of `astra-rp create-version`. */
232
+ export const CREATE_VERSION_FLAG = Object.freeze({
233
+ bump: "bump",
234
+ patch: "patch",
235
+ minor: "minor",
236
+ major: "major",
237
+ setVersion: "set-version",
238
+ dryRun: "dry-run",
239
+ skipUnpublished: "skip-unpublished",
240
+ ignoreLocalChanges: "ignore-local-changes",
241
+ acceptSuggested: "accept-suggested",
242
+ local: "local",
243
+ ci: "ci",
244
+ setupCi: "setup-ci",
245
+ ciRelease: "ci-release",
246
+ retryCi: "retry-ci",
247
+ help: "help",
248
+ /** Short flag of `--help`; public alias of the `h` entry of `CREATE_VERSION_SHORT_FLAG`. */
249
+ helpShort: "h",
250
+ endOfOptions: "--",
251
+ });
252
+
253
+ /**
254
+ * Short name of each release type: `--bump`/`-b` accepts it as a value (`-b m`) and it is also the
255
+ * short flag of the `--patch`, `--minor` and `--major` shortcuts. Case-sensitive: `m` is minor and
256
+ * `M` major.
257
+ */
258
+ export const RELEASE_TYPE_SHORT_NAME = Object.freeze({
259
+ patch: "p",
260
+ minor: "m",
261
+ major: "M",
262
+ });
263
+
264
+ /**
265
+ * Long flag of each short flag of `astra-rp create-version`. Short flags are whole tokens (`-sv` has
266
+ * two letters), so they are never grouped: `-lm` is rejected instead of read as `-l -m`. A value may
267
+ * follow as the next token or after `=` (`-b m`, `-b=m`, `-sv 1.3.0`, `-sv=1.3.0`).
268
+ */
269
+ export const CREATE_VERSION_SHORT_FLAG = Object.freeze({
270
+ b: CREATE_VERSION_FLAG.bump,
271
+ sv: CREATE_VERSION_FLAG.setVersion,
272
+ [RELEASE_TYPE_SHORT_NAME.patch]: CREATE_VERSION_FLAG.patch,
273
+ [RELEASE_TYPE_SHORT_NAME.minor]: CREATE_VERSION_FLAG.minor,
274
+ [RELEASE_TYPE_SHORT_NAME.major]: CREATE_VERSION_FLAG.major,
275
+ l: CREATE_VERSION_FLAG.local,
276
+ [CREATE_VERSION_FLAG.helpShort]: CREATE_VERSION_FLAG.help,
277
+ });
278
+
279
+ /** Single-dash token of a short flag, with an optional `=value`: `-l`, `-sv=1.3.0`; not `--local`. */
280
+ export const SHORT_FLAG_TOKEN_PATTERN = /^-(?<name>[^-=][^=]*)(?:=(?<value>.*))?$/su;
281
+
282
+ /** Message of the `git stash` entry holding the changes `--ignore-local-changes` sets aside. */
283
+ export const LOCAL_CHANGES_STASH_MESSAGE = "astra-rp create-version: cambios locales apartados durante el release";
284
+
285
+ /** Optional `v` prefix accepted in hand-typed versions. */
286
+ export const VERSION_PREFIX_PATTERN = /^v/u;
287
+
288
+ /** `version` field of `package.json`, replaced in place to keep formatting. */
289
+ export const PACKAGE_VERSION_FIELD_PATTERN = /("version"\s*:\s*")[^"]+(")/u;
290
+
291
+ /** `git log -G` pattern of a changed top-level `version` field; the last such commit is the last release. */
292
+ export const VERSION_FIELD_CHANGE_PATTERN = `"version"[[:space:]]*:`;
293
+
294
+ /** GitHub `owner/repo` inside an SSH or HTTPS remote URL. */
295
+ export const GITHUB_REPOSITORY_PATTERN = /github\.com[:/]([^/]+\/[^/]+?)(?:\.git)?$/u;
296
+
297
+ /** Separates fields inside one `git log --format` record. */
298
+ export const FIELD_SEPARATOR = "\x1f";
299
+
300
+ /** Separates records in `git log --format` output. */
301
+ export const RECORD_SEPARATOR = "\x1e";
302
+
303
+ /** Width of the `git status --porcelain` state columns before each path. */
304
+ export const PORCELAIN_STATUS_WIDTH = 3;
305
+
306
+ /** Separator between the original and the new path of a renamed or copied `git status --porcelain` entry. */
307
+ export const PORCELAIN_RENAME_SEPARATOR = " -> ";
308
+
309
+ /**
310
+ * Extensions of the files `--ignore-local-changes` refuses to set aside: the configuration is
311
+ * loaded before the changes are set aside, and it (or a hook) may import code or data from them,
312
+ * so the release would run with content that is not the committed one.
313
+ */
314
+ export const UNSETTABLE_ASIDE_EXTENSIONS = Object.freeze([".js", ".mjs", ".cjs", ".ts", ".json"]);
315
+
316
+ /** Maximum commits listed in a box. */
317
+ export const MAX_LISTED_COMMITS = 12;
318
+
319
+ /** Maximum uncommitted files, foreign commits or pending migrations listed before summarizing. */
320
+ export const MAX_LISTED_ITEMS = 5;
321
+
322
+ /** Length of the abbreviated commit ids shown to the user: the same as in changelog entries. */
323
+ export const SHORT_SHA_LENGTH = COMMIT_SHORT_SHA_LENGTH;
324
+
325
+ /** Placeholders of the `artifact` pattern: the released version and the npm package name. */
326
+ export const ARTIFACT_VERSION_PLACEHOLDER = "{version}";
327
+ export const ARTIFACT_NAME_PLACEHOLDER = "{name}";
328
+
329
+ /**
330
+ * Scope of a package name as `npm pack` and `pnpm pack` name the tarball: the
331
+ * leading `@` is dropped and the `/` becomes `-` (`@scope/pkg` → `scope-pkg`).
332
+ * The `scope` group keeps the scope without `@`.
333
+ */
334
+ export const PACKAGE_SCOPE_PATTERN = /^@(?<scope>[^/]+)\//u;
335
+
336
+ /** Replacement of {@link PACKAGE_SCOPE_PATTERN} that yields the tarball base name prefix. */
337
+ export const PACKED_SCOPE_REPLACEMENT = "$<scope>-";
338
+
339
+ /** Wildcard of an `artifact` pattern segment, such as the checksum in `releases/{version}-*`. */
340
+ export const ARTIFACT_SEGMENT_WILDCARD = "*";
341
+
342
+ /**
343
+ * Checksum placeholder: the SHA-256 of the archive, verified before publishing. It may repeat,
344
+ * in one segment or several, and every occurrence must declare the same digest.
345
+ */
346
+ export const ARTIFACT_SHA256_PLACEHOLDER = "{sha256}";
347
+
348
+ /** Lowercase hexadecimal SHA-256 digest matched by {@link ARTIFACT_SHA256_PLACEHOLDER}. */
349
+ export const SHA256_HEX_PATTERN_SOURCE = "[0-9a-f]{64}";
350
+
351
+ /**
352
+ * Characters allowed in an artifact path passed to `npm publish` through the Windows shell;
353
+ * `~` is allowed because npm package names (and so tarball names) may contain it.
354
+ */
355
+ export const SAFE_ARTIFACT_PATH_PATTERN = /^[\w.@+~/-]+$/u;
356
+
357
+ /**
358
+ * Prefix that makes npm read an artifact path as a local file: a bare
359
+ * `releases/x/pkg.tgz` operand is parsed as a package spec (a GitHub shorthand).
360
+ */
361
+ export const LOCAL_PATH_PREFIX = "./";
362
+
363
+ /**
364
+ * Arguments of the `npm pack` run that reports the integrity npm would pack from the release
365
+ * checkout: nothing is written and no lifecycle script runs, so it only reads what `prepare` left.
366
+ */
367
+ export const NPM_PACK_DRY_RUN_ARGUMENTS = Object.freeze(["pack", "--dry-run", "--json", "--ignore-scripts"]);
368
+
369
+ /**
370
+ * Prefix of the temporary directory, outside the package root, that holds the prepared archive
371
+ * while `npm pack --dry-run` runs, so npm never packs the archive into the package it describes.
372
+ */
373
+ export const ARTIFACT_HOLDING_DIRECTORY_PREFIX = "astra-rp-artifact-";
374
+
375
+ /** Node.js error code of a `rename` across file systems, retried as copy and delete. */
376
+ export const CROSS_DEVICE_RENAME_ERROR_CODE = "EXDEV";
377
+
378
+ /** Hash algorithm of the npm `integrity` string (`sha512-<base64>`). */
379
+ export const NPM_INTEGRITY_ALGORITHM = "sha512";
380
+
381
+ /** npm `integrity` string as `npm pack --json` reports it. */
382
+ export const NPM_INTEGRITY_PATTERN = /^sha512-[A-Za-z0-9+/]+={0,2}$/u;
383
+
384
+ /** Manifest field whose keys npm applies as configuration when it publishes. */
385
+ export const PUBLISH_CONFIG_FIELD = "publishConfig";
386
+
387
+ /**
388
+ * `publishConfig` keys pnpm hoists onto the packed manifest root. npm treats every
389
+ * `publishConfig` key as npm configuration and never rewrites manifest fields with it, so a
390
+ * package that declares any of these would be published differently by npm than by `pnpm pack`.
391
+ * Any other key (`registry`, `access`, `tag`, `provenance`, `@scope:registry`, `otp`...) is npm
392
+ * configuration and is accepted.
393
+ *
394
+ * Source: `PUBLISH_CONFIG_WHITELIST` in pnpm v12.6.0
395
+ * (`pnpm/crates/exportable-manifest/src/create.rs`; same list as
396
+ * `releasing/exportable-manifest/src/overridePublishConfig.ts` in pnpm 11).
397
+ *
398
+ * @see https://github.com/pnpm/pnpm/blob/v12.6.0/pnpm/crates/exportable-manifest/src/create.rs
399
+ * @see https://docs.npmjs.com/cli/v11/configuring-npm/package-json#publishconfig
400
+ */
401
+ export const PNPM_HOISTED_PUBLISH_CONFIG_KEYS = Object.freeze([
402
+ "name",
403
+ "bin",
404
+ "engines",
405
+ "type",
406
+ "imports",
407
+ "main",
408
+ "module",
409
+ "typings",
410
+ "types",
411
+ "exports",
412
+ "browser",
413
+ "esnext",
414
+ "es2015",
415
+ "unpkg",
416
+ "umd:main",
417
+ "os",
418
+ "cpu",
419
+ "libc",
420
+ "typesVersions",
421
+ ]);
422
+
423
+ /** Dependency maps npm publishes as they are written in `package.json`. */
424
+ export const PUBLISHED_DEPENDENCY_FIELDS = Object.freeze(["dependencies", "peerDependencies", "optionalDependencies"]);
425
+
426
+ /**
427
+ * Dependency specifiers only `pnpm pack` rewrites and npm publishes verbatim, which npm then
428
+ * cannot install (`EUNSUPPORTEDPROTOCOL`):
429
+ * - `catalog:` (dereferenced to the catalog entry);
430
+ * - `workspace:` (resolved to the linked package version), as the whole specifier or, in
431
+ * `peerDependencies`, as a segment of a compound range (`^1.0.0 || workspace:>=1.0.0`);
432
+ * - `jsr:` (turned into an `npm:@jsr/<scope>__<name>` alias).
433
+ *
434
+ * Source: `convert_dependency_for_publish` (catalog → workspace → jsr replacers) in pnpm v12.6.0
435
+ * `pnpm/crates/exportable-manifest/src/create.rs`, and `replace_workspace_protocol_peer_dependency`
436
+ * in `pnpm/crates/exportable-manifest/src/replace.rs`. No other protocol is rewritten there.
437
+ *
438
+ * @see https://github.com/pnpm/pnpm/blob/v12.6.0/pnpm/crates/exportable-manifest/src/create.rs
439
+ * @see https://github.com/pnpm/pnpm/blob/v12.6.0/pnpm/crates/exportable-manifest/src/replace.rs
440
+ */
441
+ export const PNPM_PACK_REWRITTEN_SPECIFIER_PATTERN = /^(?:workspace|catalog|jsr):|\|\|\s*workspace:/u;
442
+
443
+ /** Public npm registry: npm's default, used when no config sets `@scope:registry` nor `registry`. */
444
+ export const DEFAULT_NPM_REGISTRY_URL = "https://registry.npmjs.org/";
445
+
446
+ /** Prefix of a package page on npmjs.com, linked in the summary of a release published to {@link DEFAULT_NPM_REGISTRY_URL}. */
447
+ export const NPMJS_PACKAGE_PAGE_URL = "https://www.npmjs.com/package/";
448
+
449
+ /** `publishConfig` key of the registry for every package, used when no scope-specific registry applies. */
450
+ export const PUBLISH_CONFIG_REGISTRY_KEY = "registry";
451
+
452
+ /** Suffix of the scope-specific `publishConfig` registry key, as in `@scope:registry`. */
453
+ export const SCOPED_REGISTRY_KEY_SUFFIX = ":registry";
454
+
455
+ /**
456
+ * Registry URL allowed on the `npm view` command line built for the Windows shell: only characters
457
+ * without shell meaning (no `%`, `&`, `|`, `^`, quotes or spaces), after URL normalization.
458
+ */
459
+ export const SHELL_SAFE_REGISTRY_URL_PATTERN = /^https?:\/\/[\w.~:/@+-]+$/u;
460
+
461
+ /** npm option that selects the registry `npm view` queries. */
462
+ export const NPM_REGISTRY_OPTION = "--registry";
463
+
464
+ /** npm option that replaces the user config (`~/.npmrc`) with the temporary one. */
465
+ export const NPM_USER_CONFIG_OPTION = "--userconfig";
466
+
467
+ /** npm subcommand that prints the effective value of a config key. */
468
+ export const NPM_CONFIG_GET_ARGUMENTS = Object.freeze(["config", "get"]);
469
+
470
+ /** What `npm config get` prints for a key no config source sets, such as an unused `@scope:registry`. */
471
+ export const NPM_UNSET_CONFIG_VALUE = "undefined";
472
+
473
+ /** Protocols a publish registry URL may use. */
474
+ export const NPM_REGISTRY_PROTOCOLS = Object.freeze(["http:", "https:"]);
475
+
476
+ /**
477
+ * Value of the registry credential in the temporary npm config: npm expands `${NPM_TOKEN}` from
478
+ * the environment, so the token never reaches the disk or a command line.
479
+ */
480
+ export const NPM_AUTH_TOKEN_REFERENCE = `\${${NPM_TOKEN_VARIABLE}}`;
481
+
482
+ /** Prefix of the temporary directory holding the publish-only npm user config. */
483
+ export const NPM_AUTH_DIRECTORY_PREFIX = "astra-rp-npm-auth-";
484
+
485
+ /** Characters that could break out of a quoted path on the Windows shell. */
486
+ export const UNSAFE_QUOTED_PATH_PATTERN = /["%]/u;
487
+
488
+ /** Placeholder replaced by the released version in `summary` lines. */
489
+ export const SUMMARY_VERSION_PLACEHOLDER = "{version}";
490
+
491
+ /**
492
+ * Shown when syncing `main` brought new commits: the run ends (exit code 0, it is not a failure)
493
+ * so the next one loads the updated configuration and diagnoses again.
494
+ *
495
+ * @param {string} createVersionCommand - How the project runs create-version.
496
+ * @returns {string} Spanish message.
497
+ */
498
+ export const buildMainSyncedRestartMessage = (createVersionCommand) =>
499
+ `${MAIN_BRANCH} se actualizó desde origin: volvé a correr ${createVersionCommand} para diagnosticar con el código y la configuración nuevos.`;
500
+
501
+ /** {@link buildMainSyncedRestartMessage} of a pnpm project. */
502
+ export const MAIN_SYNCED_RESTART_MESSAGE = buildMainSyncedRestartMessage(DEFAULT_CREATE_VERSION_COMMAND);
503
+
504
+ /** Exit code of a release stopped by a failed step, invalid arguments or configuration. */
505
+ export const FAILURE_EXIT_CODE = 1;
506
+
507
+ /** What each release type means when a project does not describe it. */
508
+ export const DEFAULT_RELEASE_TYPE_DESCRIPTIONS = Object.freeze({
509
+ patch: "Solo arreglos o cambios internos; nada nuevo para quien lo usa.",
510
+ minor: "Funcionalidades nuevas compatibles; lo existente sigue funcionando igual.",
511
+ major: "Cambio incompatible: quien lo usa tiene que adaptarse.",
512
+ });
513
+
514
+ /**
515
+ * Default descriptions while `preMajorShift` applies to a `0.x` version: each release type carries
516
+ * the changes of the level above (a patch ships features, a minor breaking changes) and a major
517
+ * leaves `0.x`.
518
+ */
519
+ export const PRE_MAJOR_SHIFTED_RELEASE_TYPE_DESCRIPTIONS = Object.freeze({
520
+ patch: "Arreglos o funcionalidades nuevas compatibles; lo existente sigue funcionando igual.",
521
+ minor: "Cambio incompatible: quien lo usa tiene que adaptarse.",
522
+ major: "Sale de 0.x: primera versión estable 1.0.0.",
523
+ });
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Contract of `astra-rp guard-publish`, the `prepublishOnly` guard that keeps
3
+ * packages from being published by a package manager other than npm.
4
+ *
5
+ * @module constants/guard-publish
6
+ */
7
+
8
+ /**
9
+ * Environment variable package managers set for lifecycle scripts, for
10
+ * example `pnpm/12.6.0 npm/? node/v24.21.0 win32 x64`. npm also reads it as its
11
+ * `user-agent` config, so an inherited value survives `npm publish`.
12
+ */
13
+ export const PACKAGE_MANAGER_USER_AGENT_VARIABLE = "npm_config_user_agent";
14
+
15
+ /** User agent prefix of npm, the only package manager allowed to publish. */
16
+ export const ALLOWED_PUBLISH_USER_AGENT_PREFIX = "npm/";
17
+
18
+ /** Package managers whose `publish` is blocked, keyed by their user agent prefix. */
19
+ export const BLOCKED_PUBLISH_PACKAGE_MANAGERS = Object.freeze({
20
+ "pnpm/": "pnpm",
21
+ "yarn/": "yarn",
22
+ "bun/": "bun",
23
+ });
24
+
25
+ /** Exit codes of `astra-rp guard-publish`. */
26
+ export const GUARD_PUBLISH_EXIT_CODE = Object.freeze({
27
+ allowed: 0,
28
+ blocked: 1,
29
+ });
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Facade of every `astra-rp` constant, grouped by domain.
3
+ *
4
+ * @module constants
5
+ */
6
+
7
+ export * from "./build-gate.js";
8
+ export * from "./changelog.js";
9
+ export * from "./cli.js";
10
+ export * from "./guard-publish.js";
11
+ export * from "./package-manager.js";
12
+ export * from "./version-files.js";
13
+ export * from "./monorepo.js";
14
+ export * from "./terminal-ui.js";
15
+ export * from "./versions.js";
16
+ export * from "./create-version.js";
17
+ export * from "./registry.js";
18
+ export * from "./ci-release.js";
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Monorepo mode of `astra-rp create-version`: workspace discovery, per-package
3
+ * tags and the subject of the single release commit.
4
+ *
5
+ * @module constants/monorepo
6
+ */
7
+
8
+ /** `packages` value that releases the workspaces the root `package.json` declares. */
9
+ export const WORKSPACES_PACKAGES = "workspaces";
10
+
11
+ /** Placeholders of `tagFormat`. `{version}` is required. */
12
+ export const TAG_FORMAT_PLACEHOLDER = Object.freeze({
13
+ version: "{version}",
14
+ /** Last directory segment of the package (`packages/widget` → `widget`). */
15
+ component: "{component}",
16
+ /** npm name of the package (`@scope/widget`). */
17
+ name: "{name}",
18
+ });
19
+
20
+ /** Tag of each package in monorepo mode: `widget-v1.2.0` (the release-please component tag). */
21
+ export const DEFAULT_MONOREPO_TAG_FORMAT = `${TAG_FORMAT_PLACEHOLDER.component}-v${TAG_FORMAT_PLACEHOLDER.version}`;
22
+
23
+ /**
24
+ * Placeholder of `summary` replaced by the name of each released package in monorepo mode (next
25
+ * to `{version}`, its version): a line with either one is printed once per released package.
26
+ */
27
+ export const SUMMARY_PACKAGE_PLACEHOLDER = "{name}";
28
+
29
+ /** Prefix of the release commit subject: `release: @scope/a@1.2.0, @scope/b@0.3.1`. */
30
+ export const MONOREPO_RELEASE_SUBJECT_PREFIX = "release: ";
31
+
32
+ /** Separator of the released packages in the release commit subject. */
33
+ export const MONOREPO_RELEASE_ENTRY_SEPARATOR = ", ";
34
+
35
+ /** One `name@X.Y.Z` entry of the release commit subject; the name may be scoped. */
36
+ export const MONOREPO_RELEASE_ENTRY_PATTERN = /^(?<name>(?:@[a-z0-9-~][a-z0-9-._~]*\/)?[a-z0-9-~][a-z0-9-._~]*)@(?<version>(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)\.(?:0|[1-9]\d*))$/u;
37
+
38
+ /** Workspace pattern that matches every direct subdirectory: `packages/*`. */
39
+ export const WORKSPACE_WILDCARD_SUFFIX = "/*";
40
+
41
+ /** Prefix of a workspace pattern that excludes directories: `!packages/internal`. */
42
+ export const WORKSPACE_EXCLUSION_PREFIX = "!";
43
+
44
+ /** Manifest fields listing dependencies; any of them links workspace packages for change detection. */
45
+ export const DEPENDENCY_FIELDS = Object.freeze(["dependencies", "devDependencies", "peerDependencies", "optionalDependencies"]);
46
+
47
+ /** Answer of the per-package version prompt that leaves the package out of this release. */
48
+ export const SKIP_PACKAGE_CHOICE = "skip";
49
+
50
+ /** Steps of a monorepo release plan (the shared ones reuse `RELEASE_STEP`). */
51
+ export const MONOREPO_RELEASE_STEP = Object.freeze({
52
+ chooseVersions: "choose-versions",
53
+ verifyChangelogs: "verify-changelogs",
54
+ bumpPackages: "bump-packages",
55
+ pushPackages: "push-packages",
56
+ publishPackages: "publish-packages",
57
+ });