@wells-nelson/build-tools 1.1.0 → 1.1.1

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 CHANGED
@@ -70,6 +70,17 @@ on an origin its own `cachePrefix`: GitHub Pages project sites of one user all s
70
70
 
71
71
  ## Templates
72
72
 
73
- `templates/deploy-pages.yml` (replace `__REPO__`) and `templates/manifest.webmanifest`.
73
+ Copy them from `node_modules/@wells-nelson/build-tools/templates/` into a new site (see ONBOARDING.md in
74
+ the repository). The workflow templates are a few lines each: triggers, permissions and a call to one of
75
+ the library's reusable workflows (see "Reusable workflows" in the repository README), where the steps live.
76
+
77
+ - `deploy-pages.yml` → `.github/workflows/deploy.yml` (replace `__REPO__`): type-check, test, build, deploy to
78
+ Pages, with a version tag reserved before the build and a GitHub release after the deploy.
79
+ - `ci.yml` and `published-packages.yml` → `.github/workflows/` as they are: the pull request check, and the
80
+ swap from local package tarballs to published versions.
81
+ - `database.yml` → `.github/workflows/` and `supabase-ops/*.sql` → `supabase/ops/` (replace `__SCHEMA__`):
82
+ nightly encrypted backup with a test restore, keep-alive, security lint and client error digest. The SQL
83
+ stays in the site, so it can also be pasted into the Supabase SQL editor.
84
+ - `manifest.webmanifest`: for PWAs.
74
85
 
75
86
  Try the icons, manifest, `basePath` and `postbuild` in the sandbox's Build tools page.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wells-nelson/build-tools",
3
- "version": "1.1.0",
3
+ "version": "1.1.1",
4
4
  "description": "Build and deployment tooling for Wells Nelson SvelteKit PWAs: postbuild, PWA icon generator, Vite config pieces, service worker, and templates.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -0,0 +1,18 @@
1
+ # Template (@wells-nelson/build-tools): copy to .github/workflows/ci.yml as is.
2
+
3
+ name: CI
4
+
5
+ # Type-check, unit tests and a production build on every pull request (the shared site-ci.yml).
6
+ # Branch protection requires the check "ci / Check, test and build".
7
+
8
+ on:
9
+ pull_request:
10
+ branches: [main]
11
+ workflow_dispatch:
12
+
13
+ permissions:
14
+ contents: read
15
+
16
+ jobs:
17
+ ci:
18
+ uses: bnelson729/wells-nelson-components/.github/workflows/site-ci.yml@main
@@ -0,0 +1,22 @@
1
+ # Template (@wells-nelson/build-tools): copy to .github/workflows/database.yml and replace __SCHEMA__ with the
2
+ # site's Postgres schema; copy supabase-ops/ to supabase/ops/ too.
3
+
4
+ name: Database
5
+
6
+ # Nightly: encrypted backup with a test restore, keep-alive, security lint and client error digest
7
+ # for the __SCHEMA__ schema (the shared site-database.yml, running supabase/ops/). Uses the
8
+ # `database` environment; see CONTRIBUTING.md > Nightly Database workflow.
9
+
10
+ on:
11
+ schedule:
12
+ - cron: '17 6 * * *'
13
+ workflow_dispatch:
14
+
15
+ permissions:
16
+ contents: read
17
+
18
+ jobs:
19
+ database:
20
+ uses: bnelson729/wells-nelson-components/.github/workflows/site-database.yml@main
21
+ with:
22
+ schema: __SCHEMA__
@@ -1,52 +1,35 @@
1
- # GitHub Pages deploy for a SvelteKit adapter-static app.
2
- # Copy to .github/workflows/deploy.yml and replace __REPO__ with the repository name.
1
+ # Template (@wells-nelson/build-tools): copy to .github/workflows/deploy.yml and replace __REPO__ with the
2
+ # repository name (the GitHub Pages project path).
3
+
3
4
  name: Deploy to GitHub Pages
4
5
 
6
+ # Every merge to main deploys and releases a new version (the shared site-deploy.yml). Run it by
7
+ # hand to bump the minor or major version. Reads the repository variables SUPABASE_URL,
8
+ # SUPABASE_ANON_KEY and, for a custom domain, BASE_PATH.
9
+
5
10
  on:
6
11
  push:
7
12
  branches: [main]
8
13
  workflow_dispatch:
14
+ inputs:
15
+ increment:
16
+ description: Which part of the version to bump
17
+ type: choice
18
+ options: [patch, minor, major]
19
+ default: patch
9
20
 
10
- permissions:
11
- contents: read
12
- pages: write
13
- id-token: write
14
-
21
+ # One deploy at a time; a newer push waits for the running one instead of cancelling it halfway.
15
22
  concurrency:
16
23
  group: pages
17
- cancel-in-progress: true
24
+ cancel-in-progress: false
18
25
 
19
26
  jobs:
20
- build:
21
- runs-on: ubuntu-latest
22
- steps:
23
- - uses: actions/checkout@v4
24
- - uses: actions/setup-node@v4
25
- with:
26
- node-version: 24
27
- cache: npm
28
- - run: npm ci
29
- # Nothing ships unless it type-checks and its tests pass.
30
- - run: npm run check --if-present
31
- - run: npm test --if-present
32
- - run: npm run build
33
- env:
34
- # Repository variables (Settings > Secrets and variables > Actions > Variables).
35
- # Leave the Supabase ones unset to deploy a local-only build.
36
- VITE_SUPABASE_URL: ${{ vars.SUPABASE_URL }}
37
- VITE_SUPABASE_ANON_KEY: ${{ vars.SUPABASE_ANON_KEY }}
38
- # "/__REPO__" for <user>.github.io/__REPO__; set BASE_PATH to "/" for a custom domain.
39
- BASE_PATH: ${{ vars.BASE_PATH || '/__REPO__' }}
40
- - uses: actions/upload-pages-artifact@v3
41
- with:
42
- path: build
43
-
44
27
  deploy:
45
- needs: build
46
- runs-on: ubuntu-latest
47
- environment:
48
- name: github-pages
49
- url: ${{ steps.deployment.outputs.page_url }}
50
- steps:
51
- - id: deployment
52
- uses: actions/deploy-pages@v4
28
+ uses: bnelson729/wells-nelson-components/.github/workflows/site-deploy.yml@main
29
+ permissions:
30
+ contents: write
31
+ pages: write
32
+ id-token: write
33
+ with:
34
+ base-path: /__REPO__
35
+ increment: ${{ inputs.increment || 'patch' }}
@@ -0,0 +1,21 @@
1
+ # Template (@wells-nelson/build-tools): copy to .github/workflows/published-packages.yml as is.
2
+
3
+ name: Use published packages
4
+
5
+ # While a shared @wells-nelson package is tried out, package.json points at a local tarball. On a
6
+ # pull request this swaps them for the published versions, commits the result to the branch and
7
+ # runs CI again (the shared site-published-packages.yml).
8
+
9
+ on:
10
+ pull_request:
11
+ branches: [main]
12
+ paths:
13
+ - package.json
14
+ - package-lock.json
15
+
16
+ jobs:
17
+ packages:
18
+ uses: bnelson729/wells-nelson-components/.github/workflows/site-published-packages.yml@main
19
+ permissions:
20
+ contents: write
21
+ actions: write
@@ -0,0 +1,9 @@
1
+ -- Template (@wells-nelson/build-tools): copy to supabase/ops/client-errors.sql and replace __SCHEMA__ with the app's schema.
2
+ -- What the app reported in the last 24 hours, most frequent first:
3
+ -- count, kind, newest version, message.
4
+ select count(*), kind, max(version), left(replace(message, '|', '/'), 200)
5
+ from __SCHEMA__.client_errors
6
+ where created_at > now() - interval '24 hours'
7
+ group by kind, message
8
+ order by count(*) desc
9
+ limit 25;
@@ -0,0 +1,10 @@
1
+ -- Template (@wells-nelson/build-tools): copy to supabase/ops/row-counts.sql and replace __SCHEMA__ with the app's schema.
2
+ -- One line per table of the __SCHEMA__ schema: "<table> <rows>". The Database
3
+ -- workflow compares these before and after a test restore. client_errors is left out: it's a
4
+ -- log that changes while the backup runs. psql only (\gexec); the Supabase SQL editor can't run it.
5
+ select format('select %L || '' '' || count(*) from %I.%I', c.relname, n.nspname, c.relname)
6
+ from pg_class c
7
+ join pg_namespace n on n.oid = c.relnamespace
8
+ where n.nspname = '__SCHEMA__' and c.relkind in ('r', 'p') and c.relname <> 'client_errors'
9
+ order by c.relname
10
+ \gexec
@@ -0,0 +1,20 @@
1
+ -- Template (@wells-nelson/build-tools): copy to supabase/ops/scratch-stub.sql and replace __SCHEMA__ with the app's schema.
2
+ -- The parts of a Supabase database that the app's schema refers to, so its backup can be
3
+ -- restored into a plain Postgres (the Database workflow's restore test, or a local check).
4
+ -- Not for a Supabase project: those have all of this already.
5
+ create role anon nologin;
6
+ create role authenticated nologin;
7
+ create role service_role nologin;
8
+ create role supabase_admin nologin;
9
+
10
+ create schema auth;
11
+ create table auth.users (
12
+ id uuid primary key,
13
+ email text,
14
+ email_confirmed_at timestamptz,
15
+ last_sign_in_at timestamptz
16
+ );
17
+ create function auth.uid() returns uuid language sql stable as $$ select null::uuid $$;
18
+ create function auth.jwt() returns jsonb language sql stable as $$ select '{}'::jsonb $$;
19
+
20
+ create publication supabase_realtime;
@@ -0,0 +1,40 @@
1
+ -- Template (@wells-nelson/build-tools): copy to supabase/ops/security-lint.sql and replace __SCHEMA__ with the app's schema.
2
+ -- Prints one line per problem in the __SCHEMA__ schema; no output means it passed. Runs in the
3
+ -- Supabase SQL editor or with psql -f.
4
+ -- Run by the Database workflow every night, and worth running after applying a migration.
5
+
6
+ -- Every table has row level security.
7
+ select format('Table %I.%I has no row level security', n.nspname, c.relname)
8
+ from pg_class c
9
+ join pg_namespace n on n.oid = c.relnamespace
10
+ where n.nspname = '__SCHEMA__' and c.relkind in ('r', 'p') and not c.relrowsecurity
11
+
12
+ union all
13
+
14
+ -- Signed-out callers (anon) can't touch any table.
15
+ select format('anon has %s on table %I.%I', p.privilege, n.nspname, c.relname)
16
+ from pg_class c
17
+ join pg_namespace n on n.oid = c.relnamespace
18
+ cross join unnest(array['SELECT', 'INSERT', 'UPDATE', 'DELETE']) as p(privilege)
19
+ where n.nspname = '__SCHEMA__' and c.relkind in ('r', 'p', 'v') and has_table_privilege('anon', c.oid, p.privilege)
20
+
21
+ union all
22
+
23
+ -- ... nor call any function but report_client_error (trigger functions can't be called).
24
+ select format('anon can execute %s', p.oid::regprocedure)
25
+ from pg_proc p
26
+ join pg_namespace n on n.oid = p.pronamespace
27
+ where n.nspname = '__SCHEMA__'
28
+ and p.prorettype <> 'trigger'::regtype
29
+ and p.proname <> 'report_client_error'
30
+ and has_function_privilege('anon', p.oid, 'EXECUTE')
31
+
32
+ union all
33
+
34
+ -- Security definer functions pin their search_path.
35
+ select format('Security definer function %s has no search_path', p.oid::regprocedure)
36
+ from pg_proc p
37
+ join pg_namespace n on n.oid = p.pronamespace
38
+ where n.nspname = '__SCHEMA__'
39
+ and p.prosecdef
40
+ and not exists (select 1 from unnest(coalesce(p.proconfig, '{}')) as c(setting) where c.setting like 'search_path=%');