@jskit-ai/create-app 0.1.35 → 0.1.37
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/package.json
CHANGED
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -Eeuo pipefail
|
|
3
|
+
|
|
4
|
+
usage() {
|
|
5
|
+
cat <<'EOF'
|
|
6
|
+
Usage:
|
|
7
|
+
scripts/dokku-set-remote-envs-via-ssh.sh <ssh-target> <public-host>
|
|
8
|
+
|
|
9
|
+
Reads the allowlisted deploy env vars from .env, derives APP_PUBLIC_URL from
|
|
10
|
+
the public host, and pushes them to the remote Dokku app with --no-restart.
|
|
11
|
+
|
|
12
|
+
Examples:
|
|
13
|
+
scripts/dokku-set-remote-envs-via-ssh.sh dokku@example.com beepollen.appgenius.biz
|
|
14
|
+
scripts/dokku-set-remote-envs-via-ssh.sh dokku@example.com https://beepollen.appgenius.biz
|
|
15
|
+
EOF
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
die() {
|
|
19
|
+
printf 'Error: %s\n' "$*" >&2
|
|
20
|
+
exit 1
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
require_cmd() {
|
|
24
|
+
command -v "$1" >/dev/null 2>&1 || die "Required command not found: $1"
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
resolve_script_dir() {
|
|
28
|
+
cd -- "$(dirname -- "$0")" && pwd
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if [[ $# -eq 0 ]]; then
|
|
32
|
+
usage
|
|
33
|
+
exit 1
|
|
34
|
+
fi
|
|
35
|
+
|
|
36
|
+
case "${1:-}" in
|
|
37
|
+
-h|--help)
|
|
38
|
+
usage
|
|
39
|
+
exit 0
|
|
40
|
+
;;
|
|
41
|
+
esac
|
|
42
|
+
|
|
43
|
+
if [[ $# -ne 2 ]]; then
|
|
44
|
+
usage
|
|
45
|
+
exit 1
|
|
46
|
+
fi
|
|
47
|
+
|
|
48
|
+
require_cmd ssh
|
|
49
|
+
require_cmd node
|
|
50
|
+
|
|
51
|
+
SSH_TARGET="$1"
|
|
52
|
+
PUBLIC_HOST_INPUT="$2"
|
|
53
|
+
SCRIPT_DIR="$(resolve_script_dir)"
|
|
54
|
+
APP_ROOT="$(cd -- "$SCRIPT_DIR/.." && pwd)"
|
|
55
|
+
|
|
56
|
+
case "$PUBLIC_HOST_INPUT" in
|
|
57
|
+
http://*|https://*)
|
|
58
|
+
APP_PUBLIC_URL="$PUBLIC_HOST_INPUT"
|
|
59
|
+
;;
|
|
60
|
+
*)
|
|
61
|
+
APP_PUBLIC_URL="https://${PUBLIC_HOST_INPUT}"
|
|
62
|
+
;;
|
|
63
|
+
esac
|
|
64
|
+
|
|
65
|
+
APP_NAME="$(node - "$APP_ROOT" <<'NODE'
|
|
66
|
+
const fs = require("node:fs");
|
|
67
|
+
const path = require("node:path");
|
|
68
|
+
|
|
69
|
+
const appRoot = process.argv[2];
|
|
70
|
+
|
|
71
|
+
function readNameFromJson(relativePath) {
|
|
72
|
+
const absolutePath = path.join(appRoot, relativePath);
|
|
73
|
+
if (!fs.existsSync(absolutePath)) {
|
|
74
|
+
return "";
|
|
75
|
+
}
|
|
76
|
+
const source = JSON.parse(fs.readFileSync(absolutePath, "utf8"));
|
|
77
|
+
return String(source?.name || "").trim();
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const appName = readNameFromJson("app.json") || readNameFromJson("package.json");
|
|
81
|
+
if (!appName) {
|
|
82
|
+
console.error("Unable to resolve app name from app.json or package.json.");
|
|
83
|
+
process.exit(1);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
process.stdout.write(appName);
|
|
87
|
+
NODE
|
|
88
|
+
)"
|
|
89
|
+
|
|
90
|
+
set_remote_env() {
|
|
91
|
+
local key="$1"
|
|
92
|
+
local encoded_value="$2"
|
|
93
|
+
|
|
94
|
+
ssh "$SSH_TARGET" /bin/bash -s -- "$APP_NAME" "$key" "$encoded_value" <<'EOF'
|
|
95
|
+
set -Eeuo pipefail
|
|
96
|
+
|
|
97
|
+
APP_NAME="$1"
|
|
98
|
+
KEY="$2"
|
|
99
|
+
ENCODED_VALUE="$3"
|
|
100
|
+
|
|
101
|
+
command -v dokku >/dev/null 2>&1 || {
|
|
102
|
+
printf 'dokku command not found on remote host.\n' >&2
|
|
103
|
+
exit 1
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
dokku config:set --no-restart --encoded "$APP_NAME" "$KEY=$ENCODED_VALUE" >/dev/null
|
|
107
|
+
EOF
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
while IFS=$'\t' read -r key encoded_value; do
|
|
111
|
+
[[ -n "$key" ]] || continue
|
|
112
|
+
set_remote_env "$key" "$encoded_value"
|
|
113
|
+
printf 'Set %s on %s\n' "$key" "$APP_NAME"
|
|
114
|
+
done < <(node - "$APP_ROOT" "$APP_PUBLIC_URL" <<'NODE'
|
|
115
|
+
const fs = require("node:fs");
|
|
116
|
+
const path = require("node:path");
|
|
117
|
+
|
|
118
|
+
const appRoot = process.argv[2];
|
|
119
|
+
const appPublicUrl = String(process.argv[3] || "").trim();
|
|
120
|
+
const envPath = path.join(appRoot, ".env");
|
|
121
|
+
|
|
122
|
+
const requiredKeys = Object.freeze([
|
|
123
|
+
"AUTH_PROFILE_MODE",
|
|
124
|
+
"AUTH_SUPABASE_URL",
|
|
125
|
+
"AUTH_SUPABASE_PUBLISHABLE_KEY"
|
|
126
|
+
]);
|
|
127
|
+
|
|
128
|
+
const optionalKeys = Object.freeze([
|
|
129
|
+
"AI_PROVIDER",
|
|
130
|
+
"AI_API_KEY",
|
|
131
|
+
"AI_BASE_URL",
|
|
132
|
+
"AI_TIMEOUT_MS",
|
|
133
|
+
"AUTH_OAUTH_PROVIDERS",
|
|
134
|
+
"AUTH_OAUTH_DEFAULT_PROVIDER",
|
|
135
|
+
"AUTH_JWT_AUDIENCE"
|
|
136
|
+
]);
|
|
137
|
+
|
|
138
|
+
function parseDotEnv(source) {
|
|
139
|
+
const result = new Map();
|
|
140
|
+
|
|
141
|
+
for (const rawLine of String(source || "").split(/\r?\n/u)) {
|
|
142
|
+
const line = rawLine.trim();
|
|
143
|
+
if (!line || line.startsWith("#")) {
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const normalizedLine = line.startsWith("export ") ? line.slice(7).trim() : line;
|
|
148
|
+
const equalsIndex = normalizedLine.indexOf("=");
|
|
149
|
+
if (equalsIndex < 1) {
|
|
150
|
+
continue;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const key = normalizedLine.slice(0, equalsIndex).trim();
|
|
154
|
+
let value = normalizedLine.slice(equalsIndex + 1).trim();
|
|
155
|
+
if (
|
|
156
|
+
value.length >= 2 &&
|
|
157
|
+
((value.startsWith("\"") && value.endsWith("\"")) || (value.startsWith("'") && value.endsWith("'")))
|
|
158
|
+
) {
|
|
159
|
+
value = value.slice(1, -1);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
result.set(key, value);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
return result;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function toBase64(value) {
|
|
169
|
+
return Buffer.from(String(value || ""), "utf8").toString("base64");
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
if (!fs.existsSync(envPath)) {
|
|
173
|
+
console.error("Missing .env in app root.");
|
|
174
|
+
process.exit(1);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
if (!appPublicUrl) {
|
|
178
|
+
console.error("APP_PUBLIC_URL is required.");
|
|
179
|
+
process.exit(1);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
const envMap = parseDotEnv(fs.readFileSync(envPath, "utf8"));
|
|
183
|
+
const rows = [["APP_PUBLIC_URL", toBase64(appPublicUrl)]];
|
|
184
|
+
|
|
185
|
+
for (const key of requiredKeys) {
|
|
186
|
+
const value = String(envMap.get(key) || "").trim();
|
|
187
|
+
if (!value) {
|
|
188
|
+
console.error(`Missing required .env value: ${key}`);
|
|
189
|
+
process.exit(1);
|
|
190
|
+
}
|
|
191
|
+
rows.push([key, toBase64(value)]);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
for (const key of optionalKeys) {
|
|
195
|
+
const value = String(envMap.get(key) || "").trim();
|
|
196
|
+
if (!value) {
|
|
197
|
+
continue;
|
|
198
|
+
}
|
|
199
|
+
rows.push([key, toBase64(value)]);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
for (const [key, encodedValue] of rows) {
|
|
203
|
+
process.stdout.write(`${key}\t${encodedValue}\n`);
|
|
204
|
+
}
|
|
205
|
+
NODE
|
|
206
|
+
)
|
|
207
|
+
|
|
208
|
+
printf '\nDone.\n'
|
|
209
|
+
printf 'Restart when ready:\n'
|
|
210
|
+
printf ' ssh %q %q\n' "$SSH_TARGET" "dokku ps:restart $APP_NAME"
|