gemstack 0.4.0 → 0.4.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +4 -0
- data/lib/gemstack/application.rb +1 -1
- data/lib/gemstack/cli/deploy_generator.rb +1 -1
- data/lib/gemstack/cli.rb +1 -1
- data/lib/gemstack/core.rb +6 -3
- data/lib/gemstack/version.rb +1 -1
- data/templates/app/config/app.rb.tt +1 -1
- data/templates/deploy/Dockerfile.tt +8 -3
- data/templates/deploy/config/deploy.yml.tt +6 -1
- data/templates/deploy/dot_kamal/secrets.tt +5 -0
- data/templates/frontend/lib/gemstack/root-env.cjs +44 -0
- data/templates/frontend/next.config.ts +5 -0
- data/templates/frontend/package.json.tt +1 -0
- metadata +4 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: '08b7f22bd22a410de8638e6249f629fc05d73c55c451ee15aaf5060aaceed7e9'
|
|
4
|
+
data.tar.gz: c4729f7d3833d7645abf7f1ca70f7e281b9a4ec8406d0482baedf0f039668162
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 8892c3a10498fda83a04ab4323c86f29898eb250f9a4cae8f3c90aa2b32c83ae60f0c79e87459c28f6eaa7bdc99812d0acb675062a79de981ec942ec450052f1
|
|
7
|
+
data.tar.gz: b3d2dc8f1d33abb5eca014e4679e5aa8a6a37772c1fb30d5720fcc638923787902a5324aeaaa2652476e1ce0e9815693f22f149d3a8e8b33e28a4bd288868ed6
|
data/CHANGELOG.md
CHANGED
data/lib/gemstack/application.rb
CHANGED
|
@@ -7,7 +7,7 @@ module GemStack
|
|
|
7
7
|
# as a Rack app. There is one per process, available as GemStack.application.
|
|
8
8
|
#
|
|
9
9
|
# Boot sequence (idempotent):
|
|
10
|
-
# 1. load .env files
|
|
10
|
+
# 1. load .env files config.env_files
|
|
11
11
|
# 2. load config/environments/<env>.rb if present
|
|
12
12
|
# 3. run plugin hooks GemStack::Plugins
|
|
13
13
|
# 4. set up Zeitwerk for every directory in app/ (+ config.autoload_paths)
|
|
@@ -13,7 +13,7 @@ module GemStack
|
|
|
13
13
|
end
|
|
14
14
|
|
|
15
15
|
KAMAL_GEM = %(gem "kamal", require: false, group: :development # bundle exec kamal deploy (config/deploy.yml)\n)
|
|
16
|
-
# The image runs Next.js's standalone server (node frontend/server.js); the
|
|
16
|
+
# The image runs Next.js's standalone server (node -r … frontend/server.js); the
|
|
17
17
|
# Dockerfile asks for that build with GEMSTACK_NEXT_OUTPUT=standalone.
|
|
18
18
|
STANDALONE = %( output: process.env.GEMSTACK_NEXT_OUTPUT === "standalone" ? "standalone" : undefined,\n)
|
|
19
19
|
|
data/lib/gemstack/cli.rb
CHANGED
|
@@ -241,7 +241,7 @@ module GemStack
|
|
|
241
241
|
are updated, and for ones you edited you choose: overwrite, skip, see the diff, or FILE.new.
|
|
242
242
|
|
|
243
243
|
gemstack update # the latest release
|
|
244
|
-
gemstack update 0.4.
|
|
244
|
+
gemstack update 0.4.1 # a specific version
|
|
245
245
|
gemstack update --templates --dry-run # only the template step, preview
|
|
246
246
|
gemstack update --templates --from 0.3.5
|
|
247
247
|
DESC
|
data/lib/gemstack/core.rb
CHANGED
|
@@ -20,10 +20,13 @@ module GemStack
|
|
|
20
20
|
setting :name, default: -> { File.basename(root) }
|
|
21
21
|
setting :root, default: -> { Dir.pwd }
|
|
22
22
|
|
|
23
|
-
# .env files loaded at boot
|
|
23
|
+
# .env files loaded at boot from the app root, in every environment (one
|
|
24
|
+
# .env for the API and the frontend: next.config.ts reads the same files).
|
|
25
|
+
# Earlier files win; real ENV always wins. Missing files are skipped, so
|
|
26
|
+
# production containers configured through ENV are unaffected.
|
|
24
27
|
setting :env_files, default: lambda {
|
|
25
28
|
env = GemStack.env
|
|
26
|
-
|
|
29
|
+
[".env.#{env}.local", ".env.local", ".env.#{env}", ".env"]
|
|
27
30
|
}
|
|
28
31
|
|
|
29
32
|
# Root secret for signatures (storage URLs, derived keys). Production must
|
|
@@ -70,7 +73,7 @@ module GemStack
|
|
|
70
73
|
end
|
|
71
74
|
|
|
72
75
|
# First call in config/app.rb: sets the application root and loads .env
|
|
73
|
-
# files
|
|
76
|
+
# files before anything reads configuration or ENV.
|
|
74
77
|
def setup(root:)
|
|
75
78
|
config.root = root.to_s
|
|
76
79
|
load_env_files!
|
data/lib/gemstack/version.rb
CHANGED
|
@@ -9,7 +9,7 @@ require "gemstack/jobs" # background jobs (app/jobs)
|
|
|
9
9
|
require "gemstack/mail" # mailers (app/mailers)
|
|
10
10
|
# require "gemstack/storage" # file uploads — `gemstack add storage` turns this on
|
|
11
11
|
|
|
12
|
-
# Sets the application root and loads .env files (
|
|
12
|
+
# Sets the application root and loads the .env files there (the frontend reads them too).
|
|
13
13
|
GemStack.setup(root: File.expand_path("..", __dir__))
|
|
14
14
|
|
|
15
15
|
# Require the gems listed in the Gemfile for the current environment.
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
#
|
|
4
4
|
# One image runs every process; config/deploy.yml (Kamal) gives each role its command:
|
|
5
5
|
<% if frontend? -%>
|
|
6
|
-
# web node frontend/server.js
|
|
6
|
+
# web node -r … frontend/server.js Next.js (standalone server)
|
|
7
7
|
<% end -%>
|
|
8
8
|
# api bundle exec puma -C config/puma.rb Ruby API (bin/docker-entrypoint migrates first)
|
|
9
9
|
<% if jobs? -%>
|
|
@@ -13,7 +13,8 @@
|
|
|
13
13
|
# docker build -t <%= service %> .
|
|
14
14
|
#
|
|
15
15
|
# Configuration comes from the environment at runtime (SECRET_KEY_BASE,
|
|
16
|
-
# DATABASE_URL, …); nothing secret is baked into the image.
|
|
16
|
+
# DATABASE_URL, …); nothing secret is baked into the image. The frontend's
|
|
17
|
+
# NEXT_PUBLIC_* values, public by design, are compiled in at build time.
|
|
17
18
|
|
|
18
19
|
ARG RUBY_VERSION=<%= ruby_version %>
|
|
19
20
|
<% if frontend? -%>
|
|
@@ -42,7 +43,10 @@ COPY frontend/package.json frontend/package-lock.json ./
|
|
|
42
43
|
RUN npm ci
|
|
43
44
|
COPY frontend/ ./
|
|
44
45
|
ENV NEXT_TELEMETRY_DISABLED=1 GEMSTACK_NEXT_OUTPUT=standalone
|
|
45
|
-
|
|
46
|
+
# NEXT_PUBLIC_* values are compiled into the JavaScript here. They come from the
|
|
47
|
+
# root .env as a build secret (.kamal/secrets: GEMSTACK_PUBLIC_ENV), mounted where
|
|
48
|
+
# next.config.ts reads the root .env, for this step only: never stored in the image.
|
|
49
|
+
RUN --mount=type=secret,id=GEMSTACK_PUBLIC_ENV,target=/.env,required=false npm run build \
|
|
46
50
|
&& mkdir -p public && cp -r public .next/standalone/ && cp -r .next/static .next/standalone/.next/
|
|
47
51
|
<% end -%>
|
|
48
52
|
|
|
@@ -57,6 +61,7 @@ COPY --from=gems --chown=app:app /app /app
|
|
|
57
61
|
<% if frontend? -%>
|
|
58
62
|
COPY --from=frontend /usr/local/bin/node /usr/local/bin/node
|
|
59
63
|
COPY --from=frontend --chown=app:app /frontend/.next/standalone /app/frontend
|
|
64
|
+
COPY --from=frontend --chown=app:app /frontend/lib/gemstack/root-env.cjs /app/frontend/lib/gemstack/root-env.cjs
|
|
60
65
|
<% end -%>
|
|
61
66
|
ENV GEMSTACK_API_HOST=0.0.0.0 GEMSTACK_API_PORT=4000<% if frontend? %> NODE_ENV=production NEXT_TELEMETRY_DISABLED=1 PORT=3000<% end %>
|
|
62
67
|
USER app
|
|
@@ -16,7 +16,7 @@ servers:
|
|
|
16
16
|
web:
|
|
17
17
|
hosts:
|
|
18
18
|
- 192.168.0.1 # CHANGE: your server's IP or hostname
|
|
19
|
-
cmd: node frontend/server.js
|
|
19
|
+
cmd: node -r ./frontend/lib/gemstack/root-env.cjs frontend/server.js
|
|
20
20
|
env:
|
|
21
21
|
clear:
|
|
22
22
|
# Server Components call the API directly, through the alias below.
|
|
@@ -111,6 +111,11 @@ volumes:
|
|
|
111
111
|
|
|
112
112
|
builder:
|
|
113
113
|
arch: amd64
|
|
114
|
+
<% if frontend? -%>
|
|
115
|
+
# The root .env's NEXT_PUBLIC_* lines, for `next build` (see .kamal/secrets).
|
|
116
|
+
secrets:
|
|
117
|
+
- GEMSTACK_PUBLIC_ENV
|
|
118
|
+
<% end -%>
|
|
114
119
|
<% if postgresql? || mysql? || redis? -%>
|
|
115
120
|
|
|
116
121
|
accessories:
|
|
@@ -5,6 +5,11 @@
|
|
|
5
5
|
# never a secret's value. `gemstack doctor` flags values written in place.
|
|
6
6
|
|
|
7
7
|
KAMAL_REGISTRY_PASSWORD=$KAMAL_REGISTRY_PASSWORD
|
|
8
|
+
<% if frontend? -%>
|
|
9
|
+
# The frontend's NEXT_PUBLIC_* settings from the root .env (.env.production first),
|
|
10
|
+
# compiled into the JavaScript at build time — public by design, nothing else is read.
|
|
11
|
+
GEMSTACK_PUBLIC_ENV=$(grep -hsE '^(export )?NEXT_PUBLIC_' .env.production .env)
|
|
12
|
+
<% end -%>
|
|
8
13
|
SECRET_KEY_BASE=$SECRET_KEY_BASE
|
|
9
14
|
<% if postgresql? -%>
|
|
10
15
|
POSTGRES_PASSWORD=$POSTGRES_PASSWORD
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
// One .env for the whole app: the root one, which the Ruby API reads too.
|
|
2
|
+
// Loads it into process.env when required — by next.config.ts (next dev,
|
|
3
|
+
// next build, next start) and, for Next.js's standalone server, which doesn't
|
|
4
|
+
// run next.config.ts, as a preload:
|
|
5
|
+
//
|
|
6
|
+
// node -r ./lib/gemstack/root-env.cjs .next/standalone/server.js
|
|
7
|
+
//
|
|
8
|
+
// Same files and order as GemStack: .env.<env>.local, .env.local, .env.<env>,
|
|
9
|
+
// .env (earlier files win); the real environment always wins. <env> is
|
|
10
|
+
// GEMSTACK_ENV, else NODE_ENV, else production (a bare `node server.js`).
|
|
11
|
+
const { readFileSync } = require("node:fs");
|
|
12
|
+
const { resolve } = require("node:path");
|
|
13
|
+
|
|
14
|
+
const ESCAPES = { n: "\n", t: "\t", r: "\r" };
|
|
15
|
+
|
|
16
|
+
function parseValue(value) {
|
|
17
|
+
if (value.startsWith('"')) {
|
|
18
|
+
const body = /^"((?:[^"\\]|\\.)*)"/.exec(value)?.[1] ?? value.slice(1);
|
|
19
|
+
return body.replace(/\\(.)/g, (_, char) => ESCAPES[char] ?? char);
|
|
20
|
+
}
|
|
21
|
+
if (value.startsWith("'")) return /^'([^']*)'/.exec(value)?.[1] ?? value.slice(1);
|
|
22
|
+
return value.replace(/\s+#.*$/, "");
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function loadRootEnv(root = resolve(__dirname, "../../..")) {
|
|
26
|
+
const env = process.env.GEMSTACK_ENV || process.env.NODE_ENV || "production";
|
|
27
|
+
for (const file of [`.env.${env}.local`, ".env.local", `.env.${env}`, ".env"]) {
|
|
28
|
+
let source;
|
|
29
|
+
try {
|
|
30
|
+
source = readFileSync(resolve(root, file), "utf8");
|
|
31
|
+
} catch {
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
for (const line of source.split(/\r?\n/)) {
|
|
35
|
+
const match = /^\s*(?:export\s+)?([A-Za-z_][A-Za-z0-9_.]*)\s*=\s*(.*)$/.exec(line);
|
|
36
|
+
if (!match || process.env[match[1]] !== undefined) continue;
|
|
37
|
+
process.env[match[1]] = parseValue(match[2].trim());
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
loadRootEnv();
|
|
43
|
+
|
|
44
|
+
module.exports = { loadRootEnv };
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import type { NextConfig } from "next";
|
|
2
2
|
|
|
3
|
+
// The root .env (shared with the Ruby API) — here so `next build` and
|
|
4
|
+
// `next start` see it wherever they run: NEXT_PUBLIC_* values are compiled
|
|
5
|
+
// into the JavaScript at build time. See lib/gemstack/root-env.cjs.
|
|
6
|
+
require("./lib/gemstack/root-env.cjs");
|
|
7
|
+
|
|
3
8
|
// One public origin, in every environment:
|
|
4
9
|
// - `gemstack dev`: the GemStack gateway routes /api/* to Ruby before requests reach Next.js.
|
|
5
10
|
// - Production with Kamal (gemstack generate deploy): kamal-proxy routes /api/* to Ruby.
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: gemstack
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.4.
|
|
4
|
+
version: 0.4.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Adware Technologies
|
|
@@ -44,14 +44,14 @@ dependencies:
|
|
|
44
44
|
requirements:
|
|
45
45
|
- - '='
|
|
46
46
|
- !ruby/object:Gem::Version
|
|
47
|
-
version: 0.4.
|
|
47
|
+
version: 0.4.1
|
|
48
48
|
type: :runtime
|
|
49
49
|
prerelease: false
|
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
|
51
51
|
requirements:
|
|
52
52
|
- - '='
|
|
53
53
|
- !ruby/object:Gem::Version
|
|
54
|
-
version: 0.4.
|
|
54
|
+
version: 0.4.1
|
|
55
55
|
- !ruby/object:Gem::Dependency
|
|
56
56
|
name: json
|
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -346,6 +346,7 @@ files:
|
|
|
346
346
|
- templates/frontend/app/page.tsx.tt
|
|
347
347
|
- templates/frontend/app/providers.tsx
|
|
348
348
|
- templates/frontend/lib/gemstack/client.ts
|
|
349
|
+
- templates/frontend/lib/gemstack/root-env.cjs
|
|
349
350
|
- templates/frontend/next-env.d.ts
|
|
350
351
|
- templates/frontend/next.config.ts
|
|
351
352
|
- templates/frontend/package.json.tt
|