@sidebase/base-config 0.1.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 (40) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +554 -0
  3. package/dist/config.d.mts +189 -0
  4. package/dist/config.d.ts +189 -0
  5. package/dist/config.mjs +46 -0
  6. package/dist/eslint/index.d.mts +55 -0
  7. package/dist/eslint/index.d.ts +55 -0
  8. package/dist/eslint/index.mjs +278 -0
  9. package/dist/prisma/index.d.mts +74 -0
  10. package/dist/prisma/index.d.ts +74 -0
  11. package/dist/prisma/index.mjs +61 -0
  12. package/dist/shared/base-config.CuUhyvQo.d.mts +47 -0
  13. package/dist/shared/base-config.CuUhyvQo.d.ts +47 -0
  14. package/docs/migration.md +764 -0
  15. package/package.json +94 -0
  16. package/presets/base/AGENTS.md +31 -0
  17. package/presets/base/CLAUDE.md +3 -0
  18. package/presets/base/dockerignore +18 -0
  19. package/presets/base/editorconfig +12 -0
  20. package/presets/base/github/workflows/streamctl-upgrade.yml +130 -0
  21. package/presets/base/gitignore +19 -0
  22. package/presets/base/oxlintrc.json +31 -0
  23. package/presets/base/pnpm-workspace.yaml +27 -0
  24. package/presets/base/preset.json +38 -0
  25. package/presets/base/templates/pnpm/only-built-dependency.yml +1 -0
  26. package/presets/base/tsconfig.json +3 -0
  27. package/presets/base/vscode/extensions.json +8 -0
  28. package/presets/base/vscode/settings.json +43 -0
  29. package/presets/config.template.ts +18 -0
  30. package/presets/manifest.json +17 -0
  31. package/presets/nuxt-app/Dockerfile +63 -0
  32. package/presets/nuxt-app/eslint.config.ts +5 -0
  33. package/presets/nuxt-app/github/workflows/ci.yml +66 -0
  34. package/presets/nuxt-app/github/workflows/pr-preview-cleanup.yml +41 -0
  35. package/presets/nuxt-app/preset.json +67 -0
  36. package/presets/nuxt-app/prisma.config.ts +6 -0
  37. package/presets/nuxt-app/templates/ci/e2e-job.yml +39 -0
  38. package/presets/nuxt-app/templates/ci/test-job.yml +13 -0
  39. package/presets/nuxt-app/tsconfig.json +6 -0
  40. package/tsconfig.base.json +19 -0
package/package.json ADDED
@@ -0,0 +1,94 @@
1
+ {
2
+ "name": "@sidebase/base-config",
3
+ "version": "0.1.0",
4
+ "description": "Shared @sidebase base configuration for Nuxt repos: ESLint / Prisma / tsconfig factories on npm, plus the streamctl file-sync preset payload",
5
+ "keywords": [
6
+ "sidebase",
7
+ "config-sync",
8
+ "nuxt",
9
+ "eslint",
10
+ "prisma",
11
+ "streamctl"
12
+ ],
13
+ "type": "module",
14
+ "license": "MIT",
15
+ "sideEffects": false,
16
+ "homepage": "https://github.com/sidebase/base-config#readme",
17
+ "repository": {
18
+ "type": "git",
19
+ "url": "git+https://github.com/sidebase/base-config.git"
20
+ },
21
+ "bugs": {
22
+ "url": "https://github.com/sidebase/base-config/issues"
23
+ },
24
+ "publishConfig": {
25
+ "access": "public"
26
+ },
27
+ "files": [
28
+ "dist",
29
+ "docs/migration.md",
30
+ "presets",
31
+ "tsconfig.base.json"
32
+ ],
33
+ "exports": {
34
+ ".": {
35
+ "types": "./dist/config.d.ts",
36
+ "import": "./dist/config.mjs"
37
+ },
38
+ "./tsconfig.base": "./tsconfig.base.json",
39
+ "./config": {
40
+ "types": "./dist/config.d.ts",
41
+ "import": "./dist/config.mjs"
42
+ },
43
+ "./eslint": {
44
+ "types": "./dist/eslint/index.d.ts",
45
+ "import": "./dist/eslint/index.mjs"
46
+ },
47
+ "./prisma": {
48
+ "types": "./dist/prisma/index.d.ts",
49
+ "import": "./dist/prisma/index.mjs"
50
+ }
51
+ },
52
+ "engines": {
53
+ "node": ">=22"
54
+ },
55
+ "dependencies": {
56
+ "@antfu/eslint-config": "^7.4",
57
+ "ufo": "^1.6.4"
58
+ },
59
+ "peerDependencies": {
60
+ "@prisma/client": "^6.19",
61
+ "eslint": "^10.5.0",
62
+ "prisma": "^6.19"
63
+ },
64
+ "peerDependenciesMeta": {
65
+ "@prisma/client": {
66
+ "optional": true
67
+ },
68
+ "prisma": {
69
+ "optional": true
70
+ }
71
+ },
72
+ "devDependencies": {
73
+ "@arethetypeswrong/cli": "^0.18.5",
74
+ "@prisma/client": "^6.19.3",
75
+ "@sidebase/streamctl": "^0.2.0",
76
+ "@types/node": "^24.0.0",
77
+ "eslint": "^10.5.0",
78
+ "jiti": "^2.7.0",
79
+ "prisma": "^6.19.3",
80
+ "publint": "^0.3.21",
81
+ "typescript": "^6.0.0",
82
+ "unbuild": "^3.5.0",
83
+ "vitest": "^3.0.0",
84
+ "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
+ }
94
+ }
@@ -0,0 +1,31 @@
1
+ # Agent instructions
2
+
3
+ These are the shared conventions every coding agent working in this repository must
4
+ follow. They are the same across every repo in the fleet.
5
+
6
+ ## Golden rules
7
+
8
+ - Prefer small, reviewable changes; explain the intent, not just the diff.
9
+ - Match the surrounding code and existing patterns before introducing new ones.
10
+ - Never commit secrets, credentials, or generated build artifacts.
11
+ - Keep all code, comments and identifiers in English.
12
+
13
+ ## Types & correctness
14
+
15
+ - Use precise types; avoid `any` and unchecked casts. Parse and validate external input at the boundary instead of trusting it downstream.
16
+ - Handle the error and empty-result paths, not just the happy path.
17
+
18
+ ## Tests & verification
19
+
20
+ - Run the project's typecheck, lint, and test scripts before proposing a change.
21
+ - Add or update tests for the behavior you change; don't weaken existing assertions to make a change pass.
22
+
23
+ ## Commits & pull requests
24
+
25
+ - Use Conventional Commits (`feat:`, `fix:`, `refactor:`, `test:`, `docs:`).
26
+ - Keep one logical change per commit and describe the WHAT and WHY.
27
+
28
+ ## Dependencies
29
+
30
+ - Use the repository's pinned package manager; do not switch tools ad hoc.
31
+ - Justify every new dependency; prefer existing utilities or the standard library.
@@ -0,0 +1,3 @@
1
+ # CLAUDE.md
2
+
3
+ @AGENTS.md
@@ -0,0 +1,18 @@
1
+ .git
2
+ .github
3
+ node_modules
4
+ npm-debug*
5
+ .nuxt
6
+ .output
7
+ .data
8
+ dist
9
+ tests
10
+ *.log
11
+ .env
12
+ .env.*
13
+ !.env.example
14
+ # The build-stage COPY globs `.npmrc*`; keep token-bearing backups
15
+ # (`.npmrc.local`, `.npmrc.bak`, ...) out of the build context. `.npmrc` itself
16
+ # is intentionally allowed through.
17
+ .npmrc.*
18
+ .DS_Store
@@ -0,0 +1,12 @@
1
+ root = true
2
+
3
+ [*]
4
+ charset = utf-8
5
+ end_of_line = lf
6
+ indent_style = space
7
+ indent_size = 2
8
+ insert_final_newline = true
9
+ trim_trailing_whitespace = true
10
+
11
+ [*.md]
12
+ trim_trailing_whitespace = false
@@ -0,0 +1,130 @@
1
+ # Managed by streamctl (full-own, render: automation-upgrade). OFF BY DEFAULT: this
2
+ # file only lands when a repo sets `automation: { upgradePr: true }` in
3
+ # streamctl.config.ts. See the payload README "Upgrade-PR workflow" for enabling.
4
+ #
5
+ # TOKEN: the PR is opened with `secrets.STREAMCTL_PR_TOKEN` (a GitHub App
6
+ # installation token or a machine-account PAT), NOT the default `GITHUB_TOKEN`.
7
+ # A PR created with `GITHUB_TOKEN` does NOT trigger `pull_request` workflows, so
8
+ # this repo's own `check` gate would never run on the bot's PR. The bot identity
9
+ # for the fleet is still being decided; treat this file as inert and provide the
10
+ # secret before enabling. No registry token is needed: the payload is public npm.
11
+ # A repo with OTHER private dependencies must opt this file out
12
+ # (`files: { ".github/workflows/streamctl-upgrade.yml": "off" }`) and wire its own auth.
13
+ #
14
+ # Actions are pinned by full commit SHA (this workflow handles a token); the version
15
+ # tag is in the trailing comment.
16
+ name: streamctl upgrade
17
+
18
+ on:
19
+ schedule:
20
+ - cron: "0 6 * * 1" # Mondays 06:00 UTC
21
+ workflow_dispatch:
22
+
23
+ # Least privilege: every PR/issue write below uses STREAMCTL_PR_TOKEN, so the
24
+ # default token only needs to read the repo for checkout.
25
+ permissions:
26
+ contents: read
27
+
28
+ env:
29
+ NODE_VERSION: "${NODE_VERSION}"
30
+
31
+ jobs:
32
+ upgrade:
33
+ runs-on: ubuntu-latest
34
+ steps:
35
+ # A bot identity is REQUIRED for the PR (see the header). To mint an App token
36
+ # in-workflow instead of storing a PAT, uncomment and wire the App credentials,
37
+ # then use `${{ steps.bot.outputs.token }}` in place of STREAMCTL_PR_TOKEN below:
38
+ #
39
+ # - id: bot
40
+ # uses: actions/create-github-app-token@5d869da34e18e7287c1daad50e0b8ea0f506ce69 # v1.11.0
41
+ # with:
42
+ # app-id: ${{ secrets.STREAMCTL_APP_ID }}
43
+ # private-key: ${{ secrets.STREAMCTL_APP_PRIVATE_KEY }}
44
+
45
+ - name: Checkout
46
+ uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
47
+
48
+ - name: Set up pnpm
49
+ uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6.0.9
50
+ with:
51
+ run_install: false
52
+
53
+ - name: Set up Node.js
54
+ uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
55
+ with:
56
+ node-version: ${{ env.NODE_VERSION }}
57
+ cache: pnpm
58
+
59
+ - name: Install dependencies
60
+ run: pnpm install --frozen-lockfile
61
+
62
+ # Exit codes drive the branch: 4 = an update is available (proceed); 0 = up to
63
+ # date (stop, no PR); 3 = the repo already has drift (open an issue, not a PR).
64
+ - id: check
65
+ name: Check for a payload update
66
+ run: |
67
+ set +e
68
+ pnpm streamctl check --fail-on outdated --json > streamctl-check.json
69
+ echo "code=$?" >> "$GITHUB_OUTPUT"
70
+ set -e
71
+ cat streamctl-check.json
72
+
73
+ - name: Open a drift issue (repo already diverged)
74
+ if: ${{ steps.check.outputs.code == '3' }}
75
+ env:
76
+ GH_TOKEN: ${{ secrets.STREAMCTL_PR_TOKEN }}
77
+ run: |
78
+ gh issue create \
79
+ --title "streamctl: managed files have drifted" \
80
+ --label streamctl \
81
+ --body "\`streamctl check\` reports pre-existing drift, so the automated upgrade was skipped. Run \`pnpm streamctl sync\` locally, commit the result, then re-run this workflow."
82
+
83
+ # Only upgrade when an update is actually available (check exit 4).
84
+ - id: upgrade
85
+ name: Upgrade the payload
86
+ if: ${{ steps.check.outputs.code == '4' }}
87
+ run: |
88
+ set +e
89
+ pnpm streamctl upgrade --json > streamctl-upgrade.json
90
+ echo "code=$?" >> "$GITHUB_OUTPUT"
91
+ set -e
92
+ cat streamctl-upgrade.json
93
+
94
+ # exit 2 = the chained sync hit conflicts and ROLLED BACK. Re-run bumping only the
95
+ # pin + devDependency (no sync) so the PR carries a reviewable diff a human then
96
+ # reconciles with `streamctl sync --interactive`.
97
+ - name: Prepare a plan-only bump (interactive sync required)
98
+ if: ${{ steps.upgrade.outputs.code == '2' }}
99
+ run: pnpm streamctl upgrade --no-install --json > streamctl-upgrade.json
100
+
101
+ - name: Open the upgrade PR (clean reconcile)
102
+ if: ${{ steps.upgrade.outputs.code == '0' }}
103
+ uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e # v7.0.8
104
+ with:
105
+ token: ${{ secrets.STREAMCTL_PR_TOKEN }}
106
+ branch: chore/streamctl-upgrade
107
+ commit-message: "chore: upgrade the streamctl payload"
108
+ title: "chore: upgrade the streamctl payload"
109
+ body: |
110
+ Automated payload upgrade: the managed files were reconciled cleanly by
111
+ `streamctl upgrade`. Review the diff; `streamctl-upgrade.json` (in the run
112
+ logs) has the full sync summary and dependency bumps.
113
+ labels: streamctl
114
+
115
+ - name: Open a plan-only PR (conflicts need interactive sync)
116
+ if: ${{ steps.upgrade.outputs.code == '2' }}
117
+ uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e # v7.0.8
118
+ with:
119
+ token: ${{ secrets.STREAMCTL_PR_TOKEN }}
120
+ branch: chore/streamctl-upgrade
121
+ commit-message: "chore: bump the streamctl payload pin (interactive sync required)"
122
+ title: "chore: streamctl payload upgrade needs interactive sync"
123
+ body: |
124
+ The automated `streamctl upgrade` hit conflicts and rolled the sync back, so
125
+ only the payload pin + devDependency were bumped here. Finish the upgrade by
126
+ hand: check out this branch, run `pnpm streamctl sync --interactive`, resolve
127
+ each conflict, and push.
128
+ labels: |
129
+ streamctl
130
+ needs-interactive-upgrade
@@ -0,0 +1,19 @@
1
+ node_modules
2
+ .output
3
+ .nuxt
4
+ .data
5
+ dist
6
+ .env
7
+ .env.*
8
+ !.env.example
9
+ *.log
10
+ pglite-debug.log
11
+ prisma/*.db
12
+ prisma/migrations/dev
13
+ .DS_Store
14
+ # streamctl local scratch dirs/files (e.g. local.concept) stay untracked.
15
+ local.*
16
+ local.*/
17
+ # CLAUDE.md is managed by streamctl; a user-global gitignore that ignores the
18
+ # filename everywhere would silently untrack it. Force-allow it here.
19
+ !CLAUDE.md
@@ -0,0 +1,31 @@
1
+ {
2
+ "env": {
3
+ "browser": true
4
+ },
5
+ "ignorePatterns": [
6
+ "local.*",
7
+ "local.*/"
8
+ ],
9
+ "plugins": [
10
+ "unicorn",
11
+ "typescript",
12
+ "oxc"
13
+ ],
14
+ "categories": {
15
+ "correctness": "deny",
16
+ "perf": "deny",
17
+ "suspicious": "deny",
18
+ "pedantic": "deny"
19
+ },
20
+ "rules": {
21
+ "unicorn/no-useless-undefined": "off",
22
+ "eslint/no-console": "error",
23
+ "max-lines-per-function": "off",
24
+ "max-depth": "off",
25
+ "max-nested-callbacks": "off",
26
+ "max-lines": "off",
27
+ "no-warning-comments": "off",
28
+ "no-inline-comments": "off",
29
+ "no-map-spread": "off"
30
+ }
31
+ }
@@ -0,0 +1,27 @@
1
+ # Managed by streamctl (full-own, render: security). pnpm's own settings file.
2
+ #
3
+ # SUPPLY-CHAIN COOLDOWN: a version must have been published for ${MIN_RELEASE_AGE}
4
+ # minutes before pnpm will resolve it, so a compromised release has time to be caught
5
+ # and yanked before the fleet installs it. Requires pnpm >= 10.16 (baseline: 10.28.1);
6
+ # it gates fresh resolution only, so `--frozen-lockfile` installs are unaffected.
7
+ # `@sidebase/*` is exempt: the first-party scope (this payload + the streamctl CLI),
8
+ # published by the org itself, so a payload release reaches the fleet the same day.
9
+ #
10
+ # `packages: []` is REQUIRED, not decorative: pnpm defaults it to `**` whenever a
11
+ # pnpm-workspace.yaml exists, which would silently promote every nested package.json
12
+ # (test fixtures, examples) to a workspace project and break `--frozen-lockfile`.
13
+ # A real monorepo owns this key itself, so opt the file out with
14
+ # `files: { "pnpm-workspace.yaml": "off" }` in .streamctl/config.ts.
15
+ #
16
+ # `onlyBuiltDependencies` is the postinstall-script allowlist: everything else installs
17
+ # with its lifecycle scripts blocked. The baseline covers what the fleet universally
18
+ # needs; add extras via `pnpm: { onlyBuiltDependencies: [...] }` rather than running
19
+ # `pnpm approve-builds` (which writes here and would be reverted on the next sync).
20
+ packages: []
21
+ minimumReleaseAge: ${MIN_RELEASE_AGE}
22
+ minimumReleaseAgeExclude:
23
+ - "@sidebase/*"
24
+ onlyBuiltDependencies:
25
+ - "@prisma/client"
26
+ - "esbuild"
27
+ - "prisma"
@@ -0,0 +1,38 @@
1
+ {
2
+ "name": "base",
3
+ "files": [
4
+ { "path": ".editorconfig", "strategy": "block", "source": "base/editorconfig", "blockMark": "editorconfig" },
5
+ { "path": "tsconfig.json", "strategy": "full", "source": "base/tsconfig.json", "adoption": "expected" },
6
+ { "path": ".dockerignore", "strategy": "full", "source": "base/dockerignore", "adoption": "expected" },
7
+ { "path": "pnpm-workspace.yaml", "strategy": "full", "source": "base/pnpm-workspace.yaml", "render": "security", "adoption": "expected" },
8
+ { "path": ".gitignore", "strategy": "block", "source": "base/gitignore", "blockMark": "core" },
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"] },
11
+ { "path": ".vscode/extensions.json", "strategy": "merge", "source": "base/vscode/extensions.json", "projectFields": ["unwantedRecommendations"] },
12
+ { "path": "AGENTS.md", "strategy": "full", "source": "base/AGENTS.md", "adoption": "expected" },
13
+ { "path": "CLAUDE.md", "strategy": "scaffold", "source": "base/CLAUDE.md", "adoption": "expected" },
14
+ { "path": ".github/workflows/streamctl-upgrade.yml", "strategy": "full", "source": "base/github/workflows/streamctl-upgrade.yml", "render": "automation-upgrade", "enabledBy": "automation.upgradePr", "adoption": "unexpected" }
15
+ ],
16
+ "renders": {
17
+ "automation-upgrade": {
18
+ "placeholders": {
19
+ "NODE_VERSION": { "configPath": "versions.node", "default": "24.13.0", "pattern": "^[\\w.+-]+$" }
20
+ }
21
+ },
22
+ "security": {
23
+ "placeholders": {
24
+ "MIN_RELEASE_AGE": { "configPath": "security.minimumReleaseAge", "default": "10080", "pattern": "^\\d+$" }
25
+ },
26
+ "fragments": [
27
+ { "forEach": "pnpm.onlyBuiltDependencies", "source": "base/templates/pnpm/only-built-dependency.yml" }
28
+ ]
29
+ }
30
+ },
31
+ "configKeys": {
32
+ "automation.upgradePr": "boolean",
33
+ "security.minimumReleaseAge": "string",
34
+ "pnpm.onlyBuiltDependencies": "string[]",
35
+ "versions.node": "string",
36
+ "versions.pnpm": "string"
37
+ }
38
+ }
@@ -0,0 +1,3 @@
1
+ {
2
+ "extends": "@sidebase/base-config/tsconfig.base"
3
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "recommendations": [
3
+ "editorconfig.editorconfig",
4
+ "dbaeumer.vscode-eslint",
5
+ "vue.volar",
6
+ "bradlc.vscode-tailwindcss"
7
+ ]
8
+ }
@@ -0,0 +1,43 @@
1
+ {
2
+ // Disable the default formatter, use eslint instead
3
+ "prettier.enable": false,
4
+ "eslint.useFlatConfig": true,
5
+ "typescript.tsdk": "node_modules/typescript/lib",
6
+
7
+ // Auto fix
8
+ "editor.codeActionsOnSave": {
9
+ "source.fixAll.eslint": "explicit",
10
+ "source.organizeImports": "never"
11
+ },
12
+
13
+ // Silence the stylistic rules in the IDE, but still auto fix them
14
+ "eslint.rules.customizations": [
15
+ { "rule": "style/*", "severity": "off" },
16
+ { "rule": "format/*", "severity": "off" },
17
+ { "rule": "*-indent", "severity": "off" },
18
+ { "rule": "*-spacing", "severity": "off" },
19
+ { "rule": "*-spaces", "severity": "off" },
20
+ { "rule": "*-order", "severity": "off" },
21
+ { "rule": "*-dangle", "severity": "off" },
22
+ { "rule": "*-newline", "severity": "off" },
23
+ { "rule": "*quotes", "severity": "off" },
24
+ { "rule": "*semi", "severity": "off" }
25
+ ],
26
+
27
+ // Enable eslint for all supported languages
28
+ "eslint.validate": [
29
+ "javascript",
30
+ "javascriptreact",
31
+ "typescript",
32
+ "typescriptreact",
33
+ "vue",
34
+ "html",
35
+ "markdown",
36
+ "json",
37
+ "jsonc",
38
+ "yaml",
39
+ "toml",
40
+ "gql",
41
+ "graphql"
42
+ ]
43
+ }
@@ -0,0 +1,18 @@
1
+ import { defineNuxtBaseConfig } from '@sidebase/base-config'
2
+
3
+ // Scaffolded by `streamctl init`. `defineNuxtBaseConfig` gives typed editor
4
+ // inference for this payload's knobs; the CLI validates the file on every sync.
5
+ export default defineNuxtBaseConfig({
6
+ package: '__PACKAGE__',
7
+ base: '__BASE__',
8
+ version: '__VERSION__',
9
+ profile: '__PROFILE__',
10
+
11
+ // Optional knobs, uncomment to enable:
12
+ // ci: { unitTests: true, e2e: true },
13
+ // versions: { node: '24.13.0', pnpm: '10.28.1' },
14
+ // docker: { aptPackages: ['ffmpeg'] }, // extras; openssl is always installed
15
+ // security: { minimumReleaseAge: '10080' }, // minutes before pnpm installs a release; '0' disables
16
+ // pnpm: { onlyBuiltDependencies: ['sharp'] }, // extras on top of prisma + esbuild
17
+ // eslint: { trpcGuard: true },
18
+ })
@@ -0,0 +1,17 @@
1
+ {
2
+ "schemaVersion": 2,
3
+ "presets": [
4
+ "base",
5
+ "nuxt-app"
6
+ ],
7
+ "profiles": [
8
+ {
9
+ "name": "nuxt-4",
10
+ "detect": {
11
+ "dependency": "nuxt",
12
+ "majorIs": 4
13
+ }
14
+ }
15
+ ],
16
+ "defaultBase": "nuxt-app"
17
+ }
@@ -0,0 +1,63 @@
1
+ # see https://docs.docker.com/engine/reference/builder/#understand-how-arg-and-from-interact
2
+ ARG NODE_VERSION=node:${NODE_VERSION}
3
+ ARG PNPM_VERSION=${PNPM_VERSION}
4
+
5
+ # --- BUILD STAGE ---
6
+ FROM $NODE_VERSION AS production-base
7
+
8
+ # A pre-`FROM` ARG is visible only to `FROM`. Re-declare it bare to inherit the
9
+ # global value inside this stage, or $PNPM_VERSION expands to empty below.
10
+ ARG PNPM_VERSION
11
+
12
+ WORKDIR /app
13
+
14
+ # Installed directly rather than through corepack: Node 25 no longer bundles
15
+ # corepack, and `versions.node` declares no ceiling. npm's global bin is already
16
+ # on PATH, so no PNPM_HOME wiring is needed.
17
+ RUN npm i -g pnpm@$PNPM_VERSION
18
+
19
+ # Copy pnpm files
20
+ COPY package.json pnpm-lock.yaml .npmrc* ./
21
+ ${DOCKER_PRE_INSTALL}
22
+ # load packages into the virtual store using only information from a lockfile.
23
+ # --ignore-scripts: only package files exist at this layer, so lifecycle scripts
24
+ # (e.g. `postinstall: nuxt prepare`) would run against no sources; the explicit
25
+ # build steps below (docker.buildSteps) cover them against the full tree.
26
+ RUN pnpm install --ignore-scripts --frozen-lockfile --prefer-offline
27
+
28
+ ARG ARG_NUXT_BUILD_CLIENT_SOURCE_MAPS=false
29
+ ENV NUXT_BUILD_CLIENT_SOURCE_MAPS=$ARG_NUXT_BUILD_CLIENT_SOURCE_MAPS
30
+ ${DOCKER_BUILD_ARGS}
31
+ # copy the app, note .dockerignore
32
+ COPY . .
33
+
34
+ # split commands into seperate RUN to not invalidate entire cache layers
35
+ ${DOCKER_BUILD_STEPS}
36
+
37
+ # --- FINAL PRODUCTION STAGE ---
38
+ FROM $NODE_VERSION-slim AS production
39
+
40
+ # openssl is always installed: the Prisma query engine generated in the build
41
+ # stage (debian-openssl-3.0.x) dynamically links libssl3, which slim images do
42
+ # not ship. Without it the app crashes on its first query. APT_PACKAGES adds
43
+ # project-owned extras on top (docker.aptPackages knob, e.g. "ffmpeg").
44
+ ARG APT_PACKAGES="${APT_PACKAGES}"
45
+ RUN apt-get update && apt-get install -y --no-install-recommends openssl $APT_PACKAGES \
46
+ && rm -rf /var/lib/apt/lists/*
47
+
48
+ # copy necessary directories from the production-base stage to the final production
49
+ # stage, owned by the runtime uid 1000 rather than root (see the USER switch below)
50
+ COPY --chown=node:node --from=production-base /app/.output /app/.output
51
+
52
+ WORKDIR /app
53
+
54
+ ${DOCKER_PRISMA_RUNTIME}
55
+ ${DOCKER_FINAL_STAGE}
56
+ # Drop to the unprivileged `node` user (uid 1000) the base image already ships.
57
+ # FIXED and outside every knob, so an override cannot re-root the container.
58
+ # Everything the runtime reads or executes is node-owned, and `npm exec` writes
59
+ # its npx cache under /home/node/.npm, which the official image creates writable.
60
+ USER node
61
+
62
+ # start the app
63
+ CMD [ "sh", "-c", "${DOCKER_START_COMMAND}" ]
@@ -0,0 +1,5 @@
1
+ import { createSidebaseEslint } from '@sidebase/base-config/eslint'
2
+
3
+ // Project-owned wrapper: chain `.append(...)` for repo-local rules. Shared logic
4
+ // updates via the @sidebase/base-config version bump, not file re-sync.
5
+ export default createSidebaseEslint()
@@ -0,0 +1,66 @@
1
+ # Managed by streamctl (full-own, render: ci). NODE_VERSION is a render knob
2
+ # sourced from the version baseline. pnpm is not pinned here: action-setup reads
3
+ # `packageManager` from package.json, the single reconciled source.
4
+ # The build-and-deploy-* preview/staging/production suite is deferred to 0.2.0.
5
+ name: CI
6
+
7
+ on:
8
+ pull_request:
9
+ branches: [main]
10
+
11
+ # Least privilege: the jobs only read the repo. Install/build steps run
12
+ # third-party code, so a read-only default token limits a malicious script.
13
+ permissions:
14
+ contents: read
15
+
16
+ concurrency:
17
+ group: ${{ github.workflow }}-${{ github.ref }}
18
+ cancel-in-progress: true
19
+
20
+ env:
21
+ NODE_VERSION: "${NODE_VERSION}"
22
+
23
+ jobs:
24
+ lint-typecheck:
25
+ runs-on: ubuntu-latest
26
+ steps:
27
+ - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
28
+
29
+ - name: Set up pnpm
30
+ uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6.0.9
31
+ with:
32
+ run_install: false
33
+
34
+ - name: Use Node.js ${{ env.NODE_VERSION }}
35
+ uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
36
+ with:
37
+ node-version: ${{ env.NODE_VERSION }}
38
+ cache: pnpm
39
+
40
+ - run: pnpm install --frozen-lockfile
41
+ - run: pnpm streamctl check
42
+ - run: pnpm prisma format && git diff --exit-code prisma/schema.prisma
43
+ - run: pnpm prisma generate
44
+ - run: pnpm lint
45
+ - run: pnpm jsonsort -c i18n/locales/{**/*,*}.json
46
+ - run: pnpm typecheck
47
+
48
+ build:
49
+ needs: lint-typecheck
50
+ runs-on: ubuntu-latest
51
+ steps:
52
+ - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
53
+
54
+ - name: Set up pnpm
55
+ uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6.0.9
56
+ with:
57
+ run_install: false
58
+
59
+ - name: Use Node.js ${{ env.NODE_VERSION }}
60
+ uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
61
+ with:
62
+ node-version: ${{ env.NODE_VERSION }}
63
+ cache: pnpm
64
+
65
+ - run: pnpm install --frozen-lockfile
66
+ - run: pnpm nuxi prepare && pnpm prisma generate && pnpm build