@sidebase/base-config 0.1.0 → 0.2.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.
- package/README.md +84 -4
- package/dist/config.d.mts +35 -2
- package/dist/config.d.ts +35 -2
- package/dist/config.mjs +8 -2
- package/docs/migration.md +71 -9
- package/package.json +13 -11
- package/presets/base/dockerignore +9 -0
- package/presets/base/oxlintrc.json +1 -0
- package/presets/base/preset.json +8 -2
- package/presets/base/vscode/settings.json +7 -1
- package/presets/config.template.ts +2 -1
- package/presets/manifest.json +1 -1
- package/presets/nuxt-app/Dockerfile +1 -1
- package/presets/nuxt-app/github/workflows/ci.yml +3 -0
- package/presets/nuxt-app/github/workflows/pr-preview-cleanup.yml +10 -10
- package/presets/nuxt-app/preset.json +5 -1
- package/presets/nuxt-app/templates/ci/e2e-job.yml +3 -0
- package/presets/nuxt-app/templates/ci/test-job.yml +3 -0
package/README.md
CHANGED
|
@@ -134,9 +134,10 @@ The payload is validated and dogfooded against the CLI, so `@sidebase/streamctl`
|
|
|
134
134
|
`validate:presets` imports the CLI's exported manifest schema and the e2e dry-run drives the
|
|
135
135
|
real CLI binary, so both resolve `@sidebase/streamctl` from the registry.
|
|
136
136
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
137
|
+
This payload needs **streamctl >= 0.3.0**: its manifest declares `schemaVersion` 3 (the
|
|
138
|
+
`fromDependency` placeholder behind the derived Prisma ARG), which a 0.2.x CLI rejects with
|
|
139
|
+
`SCHEMA_UNSUPPORTED`. The root `streamctl.config.ts` location it documents arrived in
|
|
140
|
+
0.2.0 — see "Config location" below.
|
|
140
141
|
|
|
141
142
|
## Typed config
|
|
142
143
|
|
|
@@ -174,7 +175,7 @@ covers both.
|
|
|
174
175
|
|
|
175
176
|
`defineNuxtBaseConfig` returns the config unchanged. Its job is typed editor inference
|
|
176
177
|
for this payload's knobs: completion and type checking on `ci`, `versions`, `docker`,
|
|
177
|
-
`automation`, `security`, `pnpm`, and the whole `eslint` option surface, plus `profile`
|
|
178
|
+
`automation`, `security`, `pnpm`, `editor`, and the whole `eslint` option surface, plus `profile`
|
|
178
179
|
narrowed to the profile names that actually exist. Without it the object is an untyped
|
|
179
180
|
literal, so a typo such as `ci: { unitTest: true }` stays silent in your editor.
|
|
180
181
|
|
|
@@ -448,6 +449,39 @@ the old list before you adopt and re-add it via `pnpm.onlyBuiltDependencies` abo
|
|
|
448
449
|
files: { "pnpm-workspace.yaml": "off" },
|
|
449
450
|
```
|
|
450
451
|
|
|
452
|
+
## CI knobs
|
|
453
|
+
|
|
454
|
+
The `nuxt-app` preset ships a managed `.github/workflows/ci.yml`. Its `lint-typecheck` and
|
|
455
|
+
`build` jobs always run; the rest is knobs:
|
|
456
|
+
|
|
457
|
+
| Knob | Default | Effect |
|
|
458
|
+
| ---- | ------- | ------ |
|
|
459
|
+
| `ci.unitTests` | `false` | Add the `test` job (`pnpm test`) |
|
|
460
|
+
| `ci.e2e` | `false` | Add the `e2e` job, with a health-checked postgres service |
|
|
461
|
+
| `ci.aptPackages` | `[]` | System packages `apt-get`-installed in the `test` and `e2e` jobs |
|
|
462
|
+
|
|
463
|
+
`ci.aptPackages` is the CI counterpart to `docker.aptPackages` below: extra system packages
|
|
464
|
+
on top of what the runner image already carries, for a binary the suite needs and
|
|
465
|
+
`ubuntu-latest` does not ship. The motivating case is `libxml2-utils`, for `xmllint`.
|
|
466
|
+
|
|
467
|
+
It applies to the `test` and `e2e` jobs **only** -- never `lint-typecheck` or `build` -- and
|
|
468
|
+
installs directly after `checkout`, before `pnpm install`, so a package needed by an install
|
|
469
|
+
lifecycle script is covered as well as one needed by the tests. Leave it unset and the step
|
|
470
|
+
is skipped entirely: it renders with a guard on the value being non-empty, so the default
|
|
471
|
+
costs a no-op step rather than an `apt-get` call.
|
|
472
|
+
|
|
473
|
+
```ts
|
|
474
|
+
export default {
|
|
475
|
+
// ...
|
|
476
|
+
ci: { unitTests: true, e2e: true, aptPackages: ["libxml2-utils"] },
|
|
477
|
+
};
|
|
478
|
+
```
|
|
479
|
+
|
|
480
|
+
Package names only. Every element is rejected if it contains a shell metacharacter, and the
|
|
481
|
+
joined string is then re-validated against the Debian package-name character set (lowercase,
|
|
482
|
+
digits, `+`, `-`, `.`). Both checks exist because the rendered command deliberately leaves
|
|
483
|
+
the value unquoted, which is how several packages word-split into one `apt-get` call.
|
|
484
|
+
|
|
451
485
|
## Dockerfile knobs
|
|
452
486
|
|
|
453
487
|
The `nuxt-app` preset ships a managed `Dockerfile`. Beyond `docker.aptPackages`
|
|
@@ -464,6 +498,16 @@ out:
|
|
|
464
498
|
| `docker.prismaRuntime` | final stage | copy the schema + install the `migrate deploy` CLI |
|
|
465
499
|
| `docker.startCommand` | inside `CMD` | `prisma migrate deploy` then the node server |
|
|
466
500
|
|
|
501
|
+
A seventh knob is different in kind — a validated version, not raw text:
|
|
502
|
+
|
|
503
|
+
| Knob | Position | Default |
|
|
504
|
+
| ---- | -------- | ------- |
|
|
505
|
+
| `docker.prismaVersion` | the `ARG PRISMA_VERSION=` default inside `docker.prismaRuntime` | derived from the repo's `prisma` pin (its range floor); the baseline only when no full `x.y.z` pin exists |
|
|
506
|
+
|
|
507
|
+
It is pattern-checked (`x.y.z`, optional prerelease), so unlike the six raw-text
|
|
508
|
+
knobs it cannot inject arbitrary Dockerfile content. `--build-arg PRISMA_VERSION=`
|
|
509
|
+
still overrides at build time.
|
|
510
|
+
|
|
467
511
|
```ts
|
|
468
512
|
export default {
|
|
469
513
|
// ...
|
|
@@ -502,6 +546,42 @@ Global installs in `docker.preInstall` must use `npm i -g <tool>`, not
|
|
|
502
546
|
`pnpm add -g`: the image sets no `PNPM_HOME`, so pnpm's global bin dir is
|
|
503
547
|
undefined.
|
|
504
548
|
|
|
549
|
+
## Editor settings (`.vscode/settings.json`)
|
|
550
|
+
|
|
551
|
+
The base preset owns its own keys in `.vscode/settings.json` and leaves the rest of the file
|
|
552
|
+
to the project. Among them is i18n-ally, configured for the fleet's standard setup:
|
|
553
|
+
`@nuxtjs/i18n` with flat dotted keys under `i18n/locales`.
|
|
554
|
+
|
|
555
|
+
Everything the payload does not write is yours and survives a sync untouched -- your
|
|
556
|
+
`editor.fontSize`, your `files.exclude`, any unrelated key at all. Six of those are named in
|
|
557
|
+
the manifest as project-owned on top of that (`editor.fontSize`, `editor.rulers`,
|
|
558
|
+
`editor.formatOnSave`, `files.exclude`, `search.exclude`, `files.watcherExclude`), which
|
|
559
|
+
keeps them yours even if a later payload version starts setting them. Only the keys the
|
|
560
|
+
payload writes are reverted, and they are the ones below.
|
|
561
|
+
|
|
562
|
+
| Knob | Default | Effect |
|
|
563
|
+
| ---- | ------- | ------ |
|
|
564
|
+
| `editor.i18nSourceLanguage` | `"de"` | The locale i18n-ally translates FROM (`i18n-ally.sourceLanguage`). Payload-enforced -- see below |
|
|
565
|
+
|
|
566
|
+
```ts
|
|
567
|
+
export default {
|
|
568
|
+
// ...
|
|
569
|
+
editor: { i18nSourceLanguage: "en" },
|
|
570
|
+
};
|
|
571
|
+
```
|
|
572
|
+
|
|
573
|
+
**If your repo authors its source strings in English, set this.** The source language is
|
|
574
|
+
payload-owned, so leaving it unset does not mean "keep what I have" -- every sync writes
|
|
575
|
+
`"de"` into the file, over the top of an `"en"` you put there by hand. Nothing warns, and
|
|
576
|
+
`streamctl check` stays green afterwards, because the value it finds is the value the payload
|
|
577
|
+
intends. Setting the knob is the only thing that makes `"en"` survive a sync.
|
|
578
|
+
|
|
579
|
+
`i18n-ally.localesPaths` and `i18n-ally.keystyle` are deliberately NOT configurable: the
|
|
580
|
+
locales path and the flat key style are fleet-wide conventions, so they are enforced rather
|
|
581
|
+
than offered. Editing either one in your own `.vscode/settings.json` is reverted on the next
|
|
582
|
+
sync. A repo that genuinely needs a different layout should opt the file out
|
|
583
|
+
(`files: { ".vscode/settings.json": "off" }`) rather than fight the merge.
|
|
584
|
+
|
|
505
585
|
## Upgrade-PR workflow
|
|
506
586
|
|
|
507
587
|
The base preset ships `.github/workflows/streamctl-upgrade.yml`, a scheduled workflow
|
package/dist/config.d.mts
CHANGED
|
@@ -20,6 +20,16 @@ interface NuxtBaseCiConfig {
|
|
|
20
20
|
unitTests?: boolean;
|
|
21
21
|
/** Include the e2e job + postgres service. */
|
|
22
22
|
e2e?: boolean;
|
|
23
|
+
/**
|
|
24
|
+
* System packages apt-installed in the `test` and `e2e` jobs before
|
|
25
|
+
* `pnpm install`, for a binary the suite needs that `ubuntu-latest` does not
|
|
26
|
+
* ship (the motivating case: `libxml2-utils` for `xmllint`). Empty by default,
|
|
27
|
+
* which renders the install step inert rather than absent. Package names only:
|
|
28
|
+
* each element is metacharacter-checked, then the joined string is re-validated
|
|
29
|
+
* by the manifest pattern, because the rendered `run:` line is deliberately
|
|
30
|
+
* unquoted so word splitting reaches apt-get.
|
|
31
|
+
*/
|
|
32
|
+
aptPackages?: string[];
|
|
23
33
|
}
|
|
24
34
|
/**
|
|
25
35
|
* Optional runtime version pins (`config.versions.*`). `node` feeds every
|
|
@@ -78,6 +88,11 @@ interface NuxtBaseDockerConfig {
|
|
|
78
88
|
* this knob, so an override cannot re-root the container. Lands verbatim.
|
|
79
89
|
*/
|
|
80
90
|
prismaRuntime?: string;
|
|
91
|
+
/**
|
|
92
|
+
* Override for the runtime Prisma CLI `ARG PRISMA_VERSION` default. Derived
|
|
93
|
+
* from the repo's `prisma` pin when unset.
|
|
94
|
+
*/
|
|
95
|
+
prismaVersion?: string;
|
|
81
96
|
/**
|
|
82
97
|
* The `sh -c` argument of the final `CMD`. Defaults to
|
|
83
98
|
* `prisma migrate deploy` then the node server; override e.g. for `db push`
|
|
@@ -121,6 +136,20 @@ interface NuxtBasePnpmConfig {
|
|
|
121
136
|
*/
|
|
122
137
|
onlyBuiltDependencies?: string[];
|
|
123
138
|
}
|
|
139
|
+
/**
|
|
140
|
+
* Optional editor knobs (`config.editor.*`) rendered into the managed
|
|
141
|
+
* `.vscode/settings.json`. Only the i18n-ally source language varies across the
|
|
142
|
+
* fleet; the locales path and key style are payload-enforced.
|
|
143
|
+
*/
|
|
144
|
+
interface NuxtBaseEditorConfig {
|
|
145
|
+
/**
|
|
146
|
+
* Source locale i18n-ally translates FROM (`i18n-ally.sourceLanguage`).
|
|
147
|
+
* Default `"de"`, the fleet majority; repos authoring in English set `"en"`.
|
|
148
|
+
* A BCP-47-ish tag (`de`, `pt-BR`, `zh-Hans-CN`); the manifest's `pattern`
|
|
149
|
+
* rejects anything that could break the rendered JSON string.
|
|
150
|
+
*/
|
|
151
|
+
i18nSourceLanguage?: string;
|
|
152
|
+
}
|
|
124
153
|
/**
|
|
125
154
|
* The typed `streamctl.config.ts` shape for the `@sidebase/base-config` payload:
|
|
126
155
|
* the CLI-universal fields plus this payload's declared knobs (`ci`, `versions`,
|
|
@@ -155,6 +184,8 @@ interface NuxtBaseConfig {
|
|
|
155
184
|
security?: NuxtBaseSecurityConfig;
|
|
156
185
|
/** Optional pnpm knobs (extra build-script allowances). */
|
|
157
186
|
pnpm?: NuxtBasePnpmConfig;
|
|
187
|
+
/** Optional editor knobs (the i18n-ally source language). */
|
|
188
|
+
editor?: NuxtBaseEditorConfig;
|
|
158
189
|
/** ESLint factory options, typed with the payload's own option surface. */
|
|
159
190
|
eslint?: CreateSidebaseEslintOptions;
|
|
160
191
|
}
|
|
@@ -176,6 +207,8 @@ declare const NUXT_BASE_AUTOMATION_KEYS: string[];
|
|
|
176
207
|
declare const NUXT_BASE_SECURITY_KEYS: string[];
|
|
177
208
|
/** Runtime list of every {@link NuxtBasePnpmConfig} key. */
|
|
178
209
|
declare const NUXT_BASE_PNPM_KEYS: string[];
|
|
210
|
+
/** Runtime list of every {@link NuxtBaseEditorConfig} key. */
|
|
211
|
+
declare const NUXT_BASE_EDITOR_KEYS: string[];
|
|
179
212
|
/**
|
|
180
213
|
* Every payload KNOB dot-path {@link NuxtBaseConfig} declares (the `ci.*` and
|
|
181
214
|
* `automation.*` leaves plus the top-level knobs); excludes the CLI-universal
|
|
@@ -185,5 +218,5 @@ declare const NUXT_BASE_PNPM_KEYS: string[];
|
|
|
185
218
|
*/
|
|
186
219
|
declare const NUXT_BASE_CONFIG_KEYS: string[];
|
|
187
220
|
|
|
188
|
-
export { NUXT_BASE_AUTOMATION_KEYS, NUXT_BASE_CI_KEYS, NUXT_BASE_CONFIG_KEYS, NUXT_BASE_DOCKER_KEYS, NUXT_BASE_PNPM_KEYS, NUXT_BASE_SECURITY_KEYS, NUXT_BASE_VERSIONS_KEYS, defineNuxtBaseConfig };
|
|
189
|
-
export type { NuxtBaseAutomationConfig, NuxtBaseCiConfig, NuxtBaseConfig, NuxtBaseDockerConfig, NuxtBasePnpmConfig, NuxtBaseSecurityConfig, NuxtBaseVersionsConfig, Profile };
|
|
221
|
+
export { NUXT_BASE_AUTOMATION_KEYS, NUXT_BASE_CI_KEYS, NUXT_BASE_CONFIG_KEYS, NUXT_BASE_DOCKER_KEYS, NUXT_BASE_EDITOR_KEYS, NUXT_BASE_PNPM_KEYS, NUXT_BASE_SECURITY_KEYS, NUXT_BASE_VERSIONS_KEYS, defineNuxtBaseConfig };
|
|
222
|
+
export type { NuxtBaseAutomationConfig, NuxtBaseCiConfig, NuxtBaseConfig, NuxtBaseDockerConfig, NuxtBaseEditorConfig, NuxtBasePnpmConfig, NuxtBaseSecurityConfig, NuxtBaseVersionsConfig, Profile };
|
package/dist/config.d.ts
CHANGED
|
@@ -20,6 +20,16 @@ interface NuxtBaseCiConfig {
|
|
|
20
20
|
unitTests?: boolean;
|
|
21
21
|
/** Include the e2e job + postgres service. */
|
|
22
22
|
e2e?: boolean;
|
|
23
|
+
/**
|
|
24
|
+
* System packages apt-installed in the `test` and `e2e` jobs before
|
|
25
|
+
* `pnpm install`, for a binary the suite needs that `ubuntu-latest` does not
|
|
26
|
+
* ship (the motivating case: `libxml2-utils` for `xmllint`). Empty by default,
|
|
27
|
+
* which renders the install step inert rather than absent. Package names only:
|
|
28
|
+
* each element is metacharacter-checked, then the joined string is re-validated
|
|
29
|
+
* by the manifest pattern, because the rendered `run:` line is deliberately
|
|
30
|
+
* unquoted so word splitting reaches apt-get.
|
|
31
|
+
*/
|
|
32
|
+
aptPackages?: string[];
|
|
23
33
|
}
|
|
24
34
|
/**
|
|
25
35
|
* Optional runtime version pins (`config.versions.*`). `node` feeds every
|
|
@@ -78,6 +88,11 @@ interface NuxtBaseDockerConfig {
|
|
|
78
88
|
* this knob, so an override cannot re-root the container. Lands verbatim.
|
|
79
89
|
*/
|
|
80
90
|
prismaRuntime?: string;
|
|
91
|
+
/**
|
|
92
|
+
* Override for the runtime Prisma CLI `ARG PRISMA_VERSION` default. Derived
|
|
93
|
+
* from the repo's `prisma` pin when unset.
|
|
94
|
+
*/
|
|
95
|
+
prismaVersion?: string;
|
|
81
96
|
/**
|
|
82
97
|
* The `sh -c` argument of the final `CMD`. Defaults to
|
|
83
98
|
* `prisma migrate deploy` then the node server; override e.g. for `db push`
|
|
@@ -121,6 +136,20 @@ interface NuxtBasePnpmConfig {
|
|
|
121
136
|
*/
|
|
122
137
|
onlyBuiltDependencies?: string[];
|
|
123
138
|
}
|
|
139
|
+
/**
|
|
140
|
+
* Optional editor knobs (`config.editor.*`) rendered into the managed
|
|
141
|
+
* `.vscode/settings.json`. Only the i18n-ally source language varies across the
|
|
142
|
+
* fleet; the locales path and key style are payload-enforced.
|
|
143
|
+
*/
|
|
144
|
+
interface NuxtBaseEditorConfig {
|
|
145
|
+
/**
|
|
146
|
+
* Source locale i18n-ally translates FROM (`i18n-ally.sourceLanguage`).
|
|
147
|
+
* Default `"de"`, the fleet majority; repos authoring in English set `"en"`.
|
|
148
|
+
* A BCP-47-ish tag (`de`, `pt-BR`, `zh-Hans-CN`); the manifest's `pattern`
|
|
149
|
+
* rejects anything that could break the rendered JSON string.
|
|
150
|
+
*/
|
|
151
|
+
i18nSourceLanguage?: string;
|
|
152
|
+
}
|
|
124
153
|
/**
|
|
125
154
|
* The typed `streamctl.config.ts` shape for the `@sidebase/base-config` payload:
|
|
126
155
|
* the CLI-universal fields plus this payload's declared knobs (`ci`, `versions`,
|
|
@@ -155,6 +184,8 @@ interface NuxtBaseConfig {
|
|
|
155
184
|
security?: NuxtBaseSecurityConfig;
|
|
156
185
|
/** Optional pnpm knobs (extra build-script allowances). */
|
|
157
186
|
pnpm?: NuxtBasePnpmConfig;
|
|
187
|
+
/** Optional editor knobs (the i18n-ally source language). */
|
|
188
|
+
editor?: NuxtBaseEditorConfig;
|
|
158
189
|
/** ESLint factory options, typed with the payload's own option surface. */
|
|
159
190
|
eslint?: CreateSidebaseEslintOptions;
|
|
160
191
|
}
|
|
@@ -176,6 +207,8 @@ declare const NUXT_BASE_AUTOMATION_KEYS: string[];
|
|
|
176
207
|
declare const NUXT_BASE_SECURITY_KEYS: string[];
|
|
177
208
|
/** Runtime list of every {@link NuxtBasePnpmConfig} key. */
|
|
178
209
|
declare const NUXT_BASE_PNPM_KEYS: string[];
|
|
210
|
+
/** Runtime list of every {@link NuxtBaseEditorConfig} key. */
|
|
211
|
+
declare const NUXT_BASE_EDITOR_KEYS: string[];
|
|
179
212
|
/**
|
|
180
213
|
* Every payload KNOB dot-path {@link NuxtBaseConfig} declares (the `ci.*` and
|
|
181
214
|
* `automation.*` leaves plus the top-level knobs); excludes the CLI-universal
|
|
@@ -185,5 +218,5 @@ declare const NUXT_BASE_PNPM_KEYS: string[];
|
|
|
185
218
|
*/
|
|
186
219
|
declare const NUXT_BASE_CONFIG_KEYS: string[];
|
|
187
220
|
|
|
188
|
-
export { NUXT_BASE_AUTOMATION_KEYS, NUXT_BASE_CI_KEYS, NUXT_BASE_CONFIG_KEYS, NUXT_BASE_DOCKER_KEYS, NUXT_BASE_PNPM_KEYS, NUXT_BASE_SECURITY_KEYS, NUXT_BASE_VERSIONS_KEYS, defineNuxtBaseConfig };
|
|
189
|
-
export type { NuxtBaseAutomationConfig, NuxtBaseCiConfig, NuxtBaseConfig, NuxtBaseDockerConfig, NuxtBasePnpmConfig, NuxtBaseSecurityConfig, NuxtBaseVersionsConfig, Profile };
|
|
221
|
+
export { NUXT_BASE_AUTOMATION_KEYS, NUXT_BASE_CI_KEYS, NUXT_BASE_CONFIG_KEYS, NUXT_BASE_DOCKER_KEYS, NUXT_BASE_EDITOR_KEYS, NUXT_BASE_PNPM_KEYS, NUXT_BASE_SECURITY_KEYS, NUXT_BASE_VERSIONS_KEYS, defineNuxtBaseConfig };
|
|
222
|
+
export type { NuxtBaseAutomationConfig, NuxtBaseCiConfig, NuxtBaseConfig, NuxtBaseDockerConfig, NuxtBaseEditorConfig, NuxtBasePnpmConfig, NuxtBaseSecurityConfig, NuxtBaseVersionsConfig, Profile };
|
package/dist/config.mjs
CHANGED
|
@@ -6,7 +6,8 @@ function knobKeys(shape) {
|
|
|
6
6
|
}
|
|
7
7
|
const NUXT_BASE_CI_KEYS = knobKeys({
|
|
8
8
|
unitTests: 0,
|
|
9
|
-
e2e: 0
|
|
9
|
+
e2e: 0,
|
|
10
|
+
aptPackages: 0
|
|
10
11
|
});
|
|
11
12
|
const NUXT_BASE_VERSIONS_KEYS = knobKeys({
|
|
12
13
|
node: 0,
|
|
@@ -19,6 +20,7 @@ const NUXT_BASE_DOCKER_KEYS = knobKeys({
|
|
|
19
20
|
buildSteps: 0,
|
|
20
21
|
finalStage: 0,
|
|
21
22
|
prismaRuntime: 0,
|
|
23
|
+
prismaVersion: 0,
|
|
22
24
|
startCommand: 0
|
|
23
25
|
});
|
|
24
26
|
const NUXT_BASE_AUTOMATION_KEYS = knobKeys({
|
|
@@ -30,6 +32,9 @@ const NUXT_BASE_SECURITY_KEYS = knobKeys({
|
|
|
30
32
|
const NUXT_BASE_PNPM_KEYS = knobKeys({
|
|
31
33
|
onlyBuiltDependencies: 0
|
|
32
34
|
});
|
|
35
|
+
const NUXT_BASE_EDITOR_KEYS = knobKeys({
|
|
36
|
+
i18nSourceLanguage: 0
|
|
37
|
+
});
|
|
33
38
|
const NUXT_BASE_TOP_LEVEL_KNOBS = knobKeys({
|
|
34
39
|
eslint: 0
|
|
35
40
|
});
|
|
@@ -40,7 +45,8 @@ const NUXT_BASE_CONFIG_KEYS = [
|
|
|
40
45
|
...NUXT_BASE_AUTOMATION_KEYS.map((key) => `automation.${key}`),
|
|
41
46
|
...NUXT_BASE_SECURITY_KEYS.map((key) => `security.${key}`),
|
|
42
47
|
...NUXT_BASE_PNPM_KEYS.map((key) => `pnpm.${key}`),
|
|
48
|
+
...NUXT_BASE_EDITOR_KEYS.map((key) => `editor.${key}`),
|
|
43
49
|
...NUXT_BASE_TOP_LEVEL_KNOBS
|
|
44
50
|
];
|
|
45
51
|
|
|
46
|
-
export { NUXT_BASE_AUTOMATION_KEYS, NUXT_BASE_CI_KEYS, NUXT_BASE_CONFIG_KEYS, NUXT_BASE_DOCKER_KEYS, NUXT_BASE_PNPM_KEYS, NUXT_BASE_SECURITY_KEYS, NUXT_BASE_VERSIONS_KEYS, defineNuxtBaseConfig };
|
|
52
|
+
export { NUXT_BASE_AUTOMATION_KEYS, NUXT_BASE_CI_KEYS, NUXT_BASE_CONFIG_KEYS, NUXT_BASE_DOCKER_KEYS, NUXT_BASE_EDITOR_KEYS, NUXT_BASE_PNPM_KEYS, NUXT_BASE_SECURITY_KEYS, NUXT_BASE_VERSIONS_KEYS, defineNuxtBaseConfig };
|
package/docs/migration.md
CHANGED
|
@@ -35,11 +35,12 @@ order, so the second one is the binding constraint:
|
|
|
35
35
|
The widening came after the guard, so **a build containing the widening also contains the
|
|
36
36
|
guard, and the widening is the effective minimum.** Requiring it is sufficient.
|
|
37
37
|
|
|
38
|
-
> **Minimum version: `0.
|
|
39
|
-
>
|
|
40
|
-
> `
|
|
41
|
-
>
|
|
42
|
-
>
|
|
38
|
+
> **Minimum version: `0.3.0`.**
|
|
39
|
+
> The binding constraint is the payload manifest's `schemaVersion: 3` (the
|
|
40
|
+
> `PRISMA_VERSION_DEFAULT` placeholder uses `fromDependency`, a schema-3 feature): a 0.2.x
|
|
41
|
+
> CLI rejects the whole payload with `SCHEMA_UNSUPPORTED` ("Upgrade the CLI or the
|
|
42
|
+
> payload"). 0.2.0's own prerequisites (both above, plus reading `streamctl.config.ts`
|
|
43
|
+
> from the repo root) are of course included.
|
|
43
44
|
|
|
44
45
|
### Verify your CLI has both, without needing the version number
|
|
45
46
|
|
|
@@ -170,7 +171,7 @@ harder to tell which change caused what.
|
|
|
170
171
|
Do this BEFORE touching the config.
|
|
171
172
|
|
|
172
173
|
```sh
|
|
173
|
-
pnpm add -D @sidebase/streamctl@^0.
|
|
174
|
+
pnpm add -D @sidebase/streamctl@^0.3.0
|
|
174
175
|
```
|
|
175
176
|
|
|
176
177
|
### 3. Swap the payload package
|
|
@@ -356,14 +357,13 @@ pnpm install
|
|
|
356
357
|
migrating from `@sidestream-tech/nuxt-config` it reports something like:
|
|
357
358
|
|
|
358
359
|
```
|
|
359
|
-
[!] adoption (
|
|
360
|
+
[!] adoption (3) pre-existing file(s) streamctl now manages
|
|
360
361
|
tsconfig.json - pre-existing file streamctl now manages; adopting is expected
|
|
361
|
-
.dockerignore - pre-existing file streamctl now manages; adopting is expected
|
|
362
362
|
pnpm-workspace.yaml - pre-existing file streamctl now manages; adopting is expected
|
|
363
363
|
Dockerfile - pre-existing file streamctl now manages; adopting is expected
|
|
364
364
|
-> `sync --interactive` to adopt per file, `sync --force` to take ownership, or `--only <glob>` to scope
|
|
365
365
|
|
|
366
|
-
|
|
366
|
+
3 conflict(s) pending; see the per-kind guidance above.
|
|
367
367
|
```
|
|
368
368
|
|
|
369
369
|
This is not a failure and it is not something to route around. A fully-managed file whose
|
|
@@ -539,6 +539,68 @@ strategy only inspects its own markers, and the block is present and correct; an
|
|
|
539
539
|
outside it is invisible to the check. That is why this is a manual step rather than
|
|
540
540
|
something drift detection reports.
|
|
541
541
|
|
|
542
|
+
### 8b. Reconcile `.dockerignore` by hand
|
|
543
|
+
|
|
544
|
+
**Same cause as step 8, and equally not migration-specific.** `.dockerignore` is block-managed
|
|
545
|
+
too, so on first sync the payload appends its block to whatever your repository already had.
|
|
546
|
+
Your existing lines stay above it. Nothing is overwritten and nothing is reported.
|
|
547
|
+
|
|
548
|
+
Most of the leftovers are harmless. Ignore patterns are additive, so a duplicated `node_modules`
|
|
549
|
+
or `.env` above the block is genuinely inert -- it changes nothing about what the build context
|
|
550
|
+
carries. Delete them anyway, for a reason that is not tidiness: the detector below is the only
|
|
551
|
+
thing that will ever tell you a payload entry has started shadowing something of yours, and it
|
|
552
|
+
is not a one-shot check. A future payload version can add an entry that collides with a line you
|
|
553
|
+
kept above the block, and a file with leftover duplicates reads `AFFECTED` forever, so it can no
|
|
554
|
+
longer distinguish that from the noise. Clearing them is what keeps the check able to answer next
|
|
555
|
+
time.
|
|
556
|
+
|
|
557
|
+
**The case that bites is a negation.** `.dockerignore` is last-match-wins, and the managed block
|
|
558
|
+
is appended at the BOTTOM, so every payload entry beats anything you wrote above it. A repository
|
|
559
|
+
that deliberately un-ignored something now silently loses that:
|
|
560
|
+
|
|
561
|
+
```
|
|
562
|
+
!tests <- yours, above the block. Now dead.
|
|
563
|
+
|
|
564
|
+
# BEGIN streamctl MANAGED BLOCK dockerignore
|
|
565
|
+
...
|
|
566
|
+
tests <- payload's, below yours. Wins.
|
|
567
|
+
# END streamctl MANAGED BLOCK dockerignore
|
|
568
|
+
```
|
|
569
|
+
|
|
570
|
+
The build context stops carrying `tests/`, and the failure surfaces later and somewhere else --
|
|
571
|
+
as a `COPY` that lands nothing, or an in-image test run that cannot find its fixtures. The build
|
|
572
|
+
itself succeeds.
|
|
573
|
+
|
|
574
|
+
Check what sits above the block:
|
|
575
|
+
|
|
576
|
+
```sh
|
|
577
|
+
awk '/# BEGIN streamctl MANAGED BLOCK dockerignore/{exit} {print}' .dockerignore \
|
|
578
|
+
| command grep -qv '^[[:space:]]*\(#.*\)\?$' && echo AFFECTED || echo clean
|
|
579
|
+
```
|
|
580
|
+
|
|
581
|
+
As in step 8, use `command grep` -- the detector reads its exit code as its entire answer, and a
|
|
582
|
+
wrapped `grep` can report `clean` on an affected file.
|
|
583
|
+
|
|
584
|
+
`AFFECTED` does not mean something broke; it means read those lines and decide. Anything you
|
|
585
|
+
actually need, and every negation without exception, moves **below** the `# END` marker, which is
|
|
586
|
+
the supported extension point:
|
|
587
|
+
|
|
588
|
+
```
|
|
589
|
+
# END streamctl MANAGED BLOCK dockerignore
|
|
590
|
+
|
|
591
|
+
!tests
|
|
592
|
+
my-project-specific-dir
|
|
593
|
+
```
|
|
594
|
+
|
|
595
|
+
Finish by re-running the `AFFECTED`/`clean` detector above; it only says `clean` once nothing but
|
|
596
|
+
comments and blank lines is left above the block, so clear the harmless duplicates out too rather
|
|
597
|
+
than keeping a detector that can never go green.
|
|
598
|
+
|
|
599
|
+
**`streamctl check` will never flag any of this.** Block drift detection inspects only the marker
|
|
600
|
+
region, so the block is present and correct and the check exits 0 while your dead negation sits
|
|
601
|
+
three lines above it, permanently. This is the one step here that no tooling will ever remind you
|
|
602
|
+
to do.
|
|
603
|
+
|
|
542
604
|
### 9. Clean up what the payload no longer manages
|
|
543
605
|
|
|
544
606
|
Two different kinds of leftover, with the same cause: streamctl manages by path, so
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sidebase/base-config",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Shared @sidebase base configuration for Nuxt repos: ESLint / Prisma / tsconfig factories on npm, plus the streamctl file-sync preset payload",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"sidebase",
|
|
@@ -52,6 +52,16 @@
|
|
|
52
52
|
"engines": {
|
|
53
53
|
"node": ">=22"
|
|
54
54
|
},
|
|
55
|
+
"packageManager": "pnpm@10.29.1",
|
|
56
|
+
"scripts": {
|
|
57
|
+
"build": "unbuild",
|
|
58
|
+
"typecheck": "tsc --noEmit -p tsconfig.json && tsc -p tsconfig.test.json",
|
|
59
|
+
"test": "vitest run",
|
|
60
|
+
"lint": "eslint .",
|
|
61
|
+
"validate:presets": "node scripts/validate-presets.mjs",
|
|
62
|
+
"e2e:dry-run": "pnpm build && node scripts/e2e-dry-run.mjs",
|
|
63
|
+
"prepack": "pnpm build"
|
|
64
|
+
},
|
|
55
65
|
"dependencies": {
|
|
56
66
|
"@antfu/eslint-config": "^7.4",
|
|
57
67
|
"ufo": "^1.6.4"
|
|
@@ -72,7 +82,7 @@
|
|
|
72
82
|
"devDependencies": {
|
|
73
83
|
"@arethetypeswrong/cli": "^0.18.5",
|
|
74
84
|
"@prisma/client": "^6.19.3",
|
|
75
|
-
"@sidebase/streamctl": "^0.
|
|
85
|
+
"@sidebase/streamctl": "^0.3.0",
|
|
76
86
|
"@types/node": "^24.0.0",
|
|
77
87
|
"eslint": "^10.5.0",
|
|
78
88
|
"jiti": "^2.7.0",
|
|
@@ -82,13 +92,5 @@
|
|
|
82
92
|
"unbuild": "^3.5.0",
|
|
83
93
|
"vitest": "^3.0.0",
|
|
84
94
|
"yaml": "^2.9.0"
|
|
85
|
-
},
|
|
86
|
-
"scripts": {
|
|
87
|
-
"build": "unbuild",
|
|
88
|
-
"typecheck": "tsc --noEmit -p tsconfig.json && tsc -p tsconfig.test.json",
|
|
89
|
-
"test": "vitest run",
|
|
90
|
-
"lint": "eslint .",
|
|
91
|
-
"validate:presets": "node scripts/validate-presets.mjs",
|
|
92
|
-
"e2e:dry-run": "pnpm build && node scripts/e2e-dry-run.mjs"
|
|
93
95
|
}
|
|
94
|
-
}
|
|
96
|
+
}
|
|
@@ -6,6 +6,7 @@ npm-debug*
|
|
|
6
6
|
.output
|
|
7
7
|
.data
|
|
8
8
|
dist
|
|
9
|
+
test
|
|
9
10
|
tests
|
|
10
11
|
*.log
|
|
11
12
|
.env
|
|
@@ -16,3 +17,11 @@ tests
|
|
|
16
17
|
# is intentionally allowed through.
|
|
17
18
|
.npmrc.*
|
|
18
19
|
.DS_Store
|
|
20
|
+
# Local dev state written by `pnpm db` / `docker compose up`. `prisma/pglite-data`
|
|
21
|
+
# is tens of MB; `prisma/local.postgres_data` is root-owned, which fails a rootless
|
|
22
|
+
# `docker build` outright. Patterns are anchored to the context root here (unlike
|
|
23
|
+
# .gitignore), so `**/local.*` is required to reach the nested paths.
|
|
24
|
+
prisma/client
|
|
25
|
+
prisma/pglite-data
|
|
26
|
+
pgliteHealthz
|
|
27
|
+
**/local.*
|
package/presets/base/preset.json
CHANGED
|
@@ -3,11 +3,11 @@
|
|
|
3
3
|
"files": [
|
|
4
4
|
{ "path": ".editorconfig", "strategy": "block", "source": "base/editorconfig", "blockMark": "editorconfig" },
|
|
5
5
|
{ "path": "tsconfig.json", "strategy": "full", "source": "base/tsconfig.json", "adoption": "expected" },
|
|
6
|
-
{ "path": ".dockerignore", "strategy": "
|
|
6
|
+
{ "path": ".dockerignore", "strategy": "block", "source": "base/dockerignore", "blockMark": "dockerignore" },
|
|
7
7
|
{ "path": "pnpm-workspace.yaml", "strategy": "full", "source": "base/pnpm-workspace.yaml", "render": "security", "adoption": "expected" },
|
|
8
8
|
{ "path": ".gitignore", "strategy": "block", "source": "base/gitignore", "blockMark": "core" },
|
|
9
9
|
{ "path": ".oxlintrc.json", "strategy": "full", "source": "base/oxlintrc.json", "adoption": "expected" },
|
|
10
|
-
{ "path": ".vscode/settings.json", "strategy": "merge", "source": "base/vscode/settings.json", "projectFields": ["editor.fontSize", "editor.rulers", "editor.formatOnSave", "files.exclude", "search.exclude", "files.watcherExclude"] },
|
|
10
|
+
{ "path": ".vscode/settings.json", "strategy": "merge", "source": "base/vscode/settings.json", "render": "editor", "projectFields": ["editor.fontSize", "editor.rulers", "editor.formatOnSave", "files.exclude", "search.exclude", "files.watcherExclude"] },
|
|
11
11
|
{ "path": ".vscode/extensions.json", "strategy": "merge", "source": "base/vscode/extensions.json", "projectFields": ["unwantedRecommendations"] },
|
|
12
12
|
{ "path": "AGENTS.md", "strategy": "full", "source": "base/AGENTS.md", "adoption": "expected" },
|
|
13
13
|
{ "path": "CLAUDE.md", "strategy": "scaffold", "source": "base/CLAUDE.md", "adoption": "expected" },
|
|
@@ -19,6 +19,11 @@
|
|
|
19
19
|
"NODE_VERSION": { "configPath": "versions.node", "default": "24.13.0", "pattern": "^[\\w.+-]+$" }
|
|
20
20
|
}
|
|
21
21
|
},
|
|
22
|
+
"editor": {
|
|
23
|
+
"placeholders": {
|
|
24
|
+
"I18N_SOURCE_LANGUAGE": { "configPath": "editor.i18nSourceLanguage", "default": "de", "pattern": "^[a-z]{2,3}(-[A-Za-z0-9]{2,8})*$" }
|
|
25
|
+
}
|
|
26
|
+
},
|
|
22
27
|
"security": {
|
|
23
28
|
"placeholders": {
|
|
24
29
|
"MIN_RELEASE_AGE": { "configPath": "security.minimumReleaseAge", "default": "10080", "pattern": "^\\d+$" }
|
|
@@ -30,6 +35,7 @@
|
|
|
30
35
|
},
|
|
31
36
|
"configKeys": {
|
|
32
37
|
"automation.upgradePr": "boolean",
|
|
38
|
+
"editor.i18nSourceLanguage": "string",
|
|
33
39
|
"security.minimumReleaseAge": "string",
|
|
34
40
|
"pnpm.onlyBuiltDependencies": "string[]",
|
|
35
41
|
"versions.node": "string",
|
|
@@ -39,5 +39,11 @@
|
|
|
39
39
|
"toml",
|
|
40
40
|
"gql",
|
|
41
41
|
"graphql"
|
|
42
|
-
]
|
|
42
|
+
],
|
|
43
|
+
|
|
44
|
+
// i18n-ally: the fleet standard is @nuxtjs/i18n with flat dotted keys in
|
|
45
|
+
// i18n/locales. sourceLanguage is the one field that varies, so it is a knob.
|
|
46
|
+
"i18n-ally.localesPaths": ["i18n/locales"],
|
|
47
|
+
"i18n-ally.keystyle": "flat",
|
|
48
|
+
"i18n-ally.sourceLanguage": "${I18N_SOURCE_LANGUAGE}"
|
|
43
49
|
}
|
|
@@ -9,10 +9,11 @@ export default defineNuxtBaseConfig({
|
|
|
9
9
|
profile: '__PROFILE__',
|
|
10
10
|
|
|
11
11
|
// Optional knobs, uncomment to enable:
|
|
12
|
-
// ci: { unitTests: true, e2e: true },
|
|
12
|
+
// ci: { unitTests: true, e2e: true, aptPackages: ['libxml2-utils'] }, // apt extras for the test/e2e jobs
|
|
13
13
|
// versions: { node: '24.13.0', pnpm: '10.28.1' },
|
|
14
14
|
// docker: { aptPackages: ['ffmpeg'] }, // extras; openssl is always installed
|
|
15
15
|
// security: { minimumReleaseAge: '10080' }, // minutes before pnpm installs a release; '0' disables
|
|
16
16
|
// pnpm: { onlyBuiltDependencies: ['sharp'] }, // extras on top of prisma + esbuild
|
|
17
|
+
// editor: { i18nSourceLanguage: 'en' }, // i18n-ally source language (default: 'de')
|
|
17
18
|
// eslint: { trpcGuard: true },
|
|
18
19
|
})
|
package/presets/manifest.json
CHANGED
|
@@ -31,7 +31,7 @@ ${DOCKER_BUILD_ARGS}
|
|
|
31
31
|
# copy the app, note .dockerignore
|
|
32
32
|
COPY . .
|
|
33
33
|
|
|
34
|
-
# split commands into
|
|
34
|
+
# split commands into separate RUN to not invalidate entire cache layers
|
|
35
35
|
${DOCKER_BUILD_STEPS}
|
|
36
36
|
|
|
37
37
|
# --- FINAL PRODUCTION STAGE ---
|
|
@@ -28,14 +28,14 @@ jobs:
|
|
|
28
28
|
const { owner, repo } = context.repo;
|
|
29
29
|
const issue_number = context.issue.number;
|
|
30
30
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
31
|
+
// check first if the label exists on the PR
|
|
32
|
+
const { data: labels } = await github.rest.issues.listLabelsOnIssue({
|
|
33
|
+
owner,
|
|
34
|
+
repo,
|
|
35
|
+
issue_number
|
|
36
|
+
});
|
|
37
37
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
38
|
+
const hasPreviewDeployedLabel = labels.some(label => label.name === 'preview-deployed');
|
|
39
|
+
if (hasPreviewDeployedLabel) {
|
|
40
|
+
await github.rest.issues.removeLabel({ owner, repo, issue_number, name: 'preview-deployed'});
|
|
41
|
+
}
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
"renders": {
|
|
13
13
|
"ci": {
|
|
14
14
|
"placeholders": {
|
|
15
|
+
"CI_APT_PACKAGES": { "configPath": "ci.aptPackages", "default": "", "pattern": "^$|^[a-z0-9][a-z0-9 +.-]*$", "join": "space" },
|
|
15
16
|
"NODE_VERSION": { "configPath": "versions.node", "default": "24.13.0", "pattern": "^[\\w.+-]+$" }
|
|
16
17
|
},
|
|
17
18
|
"fragments": [
|
|
@@ -28,7 +29,8 @@
|
|
|
28
29
|
"DOCKER_BUILD_ARGS": { "configPath": "docker.buildArgs", "default": "" },
|
|
29
30
|
"DOCKER_BUILD_STEPS": { "configPath": "docker.buildSteps", "default": "RUN pnpm nuxi prepare\nRUN pnpm prisma generate\nRUN pnpm run build" },
|
|
30
31
|
"DOCKER_FINAL_STAGE": { "configPath": "docker.finalStage", "default": "" },
|
|
31
|
-
"DOCKER_PRISMA_RUNTIME": { "configPath": "docker.prismaRuntime", "default": "COPY --chown=node:node --from=production-base /app/prisma /app/prisma\n\n# Prisma CLI version for `migrate deploy`. Defaults to the baseline; override with --build-arg.\nARG PRISMA_VERSION
|
|
32
|
+
"DOCKER_PRISMA_RUNTIME": { "configPath": "docker.prismaRuntime", "default": "COPY --chown=node:node --from=production-base /app/prisma /app/prisma\n\n# Prisma CLI version for `migrate deploy`. Defaults to the baseline; override with --build-arg.\nARG PRISMA_VERSION=${PRISMA_VERSION_DEFAULT}\n\n# install prisma to run the `migrate deploy`. Runs as root because /app is\n# root-owned from WORKDIR; hand the install output to the runtime user in the\n# same layer so no later chown duplicates node_modules.\nRUN npm i -D prisma@${PRISMA_VERSION} && chown -R node:node /app/node_modules" },
|
|
33
|
+
"PRISMA_VERSION_DEFAULT": { "configPath": "docker.prismaVersion", "fromDependency": "prisma", "default": "6.19.1", "pattern": "^\\d+\\.\\d+\\.\\d+(?:-[0-9A-Za-z.-]+)?$" },
|
|
32
34
|
"DOCKER_START_COMMAND": { "configPath": "docker.startCommand", "default": "npm exec prisma migrate deploy && node --max-old-space-size-percentage=75 .output/server/index.mjs" }
|
|
33
35
|
},
|
|
34
36
|
"passthrough": ["PRISMA_VERSION"]
|
|
@@ -37,12 +39,14 @@
|
|
|
37
39
|
"configKeys": {
|
|
38
40
|
"ci.unitTests": "boolean",
|
|
39
41
|
"ci.e2e": "boolean",
|
|
42
|
+
"ci.aptPackages": "string[]",
|
|
40
43
|
"docker.aptPackages": "string[]",
|
|
41
44
|
"docker.preInstall": "string",
|
|
42
45
|
"docker.buildArgs": "string",
|
|
43
46
|
"docker.buildSteps": "string",
|
|
44
47
|
"docker.finalStage": "string",
|
|
45
48
|
"docker.prismaRuntime": "string",
|
|
49
|
+
"docker.prismaVersion": "string",
|
|
46
50
|
"docker.startCommand": "string",
|
|
47
51
|
"eslint": "object"
|
|
48
52
|
},
|
|
@@ -23,6 +23,9 @@
|
|
|
23
23
|
--health-retries 5
|
|
24
24
|
steps:
|
|
25
25
|
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
|
26
|
+
- name: Install apt packages
|
|
27
|
+
if: ${{ env.CI_APT_PACKAGES != '' }}
|
|
28
|
+
run: sudo apt-get update && sudo apt-get install -y --no-install-recommends $CI_APT_PACKAGES
|
|
26
29
|
- uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6.0.9
|
|
27
30
|
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
|
28
31
|
with:
|
|
@@ -2,6 +2,9 @@
|
|
|
2
2
|
runs-on: ubuntu-latest
|
|
3
3
|
steps:
|
|
4
4
|
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
|
5
|
+
- name: Install apt packages
|
|
6
|
+
if: ${{ env.CI_APT_PACKAGES != '' }}
|
|
7
|
+
run: sudo apt-get update && sudo apt-get install -y --no-install-recommends $CI_APT_PACKAGES
|
|
5
8
|
- uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6.0.9
|
|
6
9
|
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
|
7
10
|
with:
|