@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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jskit-ai/create-app",
3
- "version": "0.1.35",
3
+ "version": "0.1.37",
4
4
  "description": "Scaffold minimal JSKIT app shells.",
5
5
  "type": "module",
6
6
  "files": [
@@ -1 +1,2 @@
1
+ release: npm run db:migrate
1
2
  web: npm run start
@@ -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"