nightpay 0.3.11 → 0.4.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.

Potentially problematic release.


This version of nightpay might be problematic. Click here for more details.

@@ -1,384 +0,0 @@
1
- #!/usr/bin/env bash
2
- set -euo pipefail
3
-
4
- ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
5
- ENV_FILE="${ROOT_DIR}/.agent-playground.env"
6
- STATE_DIR="${ROOT_DIR}/.agent-playground"
7
- RUN_DIR="${STATE_DIR}/run"
8
- LOG_DIR="${STATE_DIR}/logs"
9
- MIP_PID_FILE="${RUN_DIR}/mip003.pid"
10
- UI_PID_FILE="${RUN_DIR}/ui.pid"
11
- MIP_LOG_FILE="${LOG_DIR}/mip003.log"
12
- UI_LOG_FILE="${LOG_DIR}/ui.log"
13
-
14
- PYTHON_CMD=()
15
-
16
- usage() {
17
- cat <<'EOF'
18
- Usage:
19
- bash scripts/agent-playground-setup.sh init [--force]
20
- bash scripts/agent-playground-setup.sh start
21
- bash scripts/agent-playground-setup.sh stop
22
- bash scripts/agent-playground-setup.sh doctor
23
- bash scripts/agent-playground-setup.sh status
24
- bash scripts/agent-playground-setup.sh ops-token [minutes]
25
- EOF
26
- }
27
-
28
- detect_python() {
29
- if command -v python3 >/dev/null 2>&1; then
30
- local py3
31
- py3="$(command -v python3)"
32
- if [[ "$py3" != *"WindowsApps"* ]]; then
33
- PYTHON_CMD=(python3)
34
- return 0
35
- fi
36
- fi
37
- if command -v python >/dev/null 2>&1; then
38
- PYTHON_CMD=(python)
39
- return 0
40
- fi
41
- if command -v py >/dev/null 2>&1; then
42
- PYTHON_CMD=(py -3)
43
- return 0
44
- fi
45
- return 1
46
- }
47
-
48
- generate_hex_32() {
49
- if command -v openssl >/dev/null 2>&1; then
50
- openssl rand -hex 32 | tr -d '[:space:]'
51
- return 0
52
- fi
53
-
54
- detect_python || {
55
- echo "ERROR: openssl or python3/python/py is required to generate secrets." >&2
56
- exit 1
57
- }
58
-
59
- "${PYTHON_CMD[@]}" - <<'PY'
60
- import secrets
61
- print(secrets.token_hex(32))
62
- PY
63
- }
64
-
65
- ensure_dirs() {
66
- mkdir -p "$RUN_DIR" "$LOG_DIR"
67
- }
68
-
69
- is_pid_running() {
70
- local pid_file="$1"
71
- [[ -f "$pid_file" ]] || return 1
72
- local pid
73
- pid="$(cat "$pid_file" 2>/dev/null || true)"
74
- [[ -n "$pid" ]] || return 1
75
- kill -0 "$pid" 2>/dev/null
76
- }
77
-
78
- stop_pid() {
79
- local name="$1"
80
- local pid_file="$2"
81
- if ! [[ -f "$pid_file" ]]; then
82
- return 0
83
- fi
84
- local pid
85
- pid="$(cat "$pid_file" 2>/dev/null || true)"
86
- if [[ -z "$pid" ]]; then
87
- rm -f "$pid_file"
88
- return 0
89
- fi
90
- if kill -0 "$pid" 2>/dev/null; then
91
- kill "$pid" 2>/dev/null || true
92
- sleep 1
93
- if kill -0 "$pid" 2>/dev/null; then
94
- kill -9 "$pid" 2>/dev/null || true
95
- fi
96
- echo "stopped: $name (pid $pid)"
97
- fi
98
- rm -f "$pid_file"
99
- }
100
-
101
- start_process() {
102
- local name="$1"
103
- local pid_file="$2"
104
- local log_file="$3"
105
- shift 3
106
-
107
- if is_pid_running "$pid_file"; then
108
- local running_pid
109
- running_pid="$(cat "$pid_file")"
110
- echo "already running: $name (pid $running_pid)"
111
- return 0
112
- fi
113
-
114
- nohup "$@" >>"$log_file" 2>&1 &
115
- local pid=$!
116
- echo "$pid" >"$pid_file"
117
- sleep 1
118
-
119
- if ! kill -0 "$pid" 2>/dev/null; then
120
- echo "ERROR: failed to start $name. Check log: $log_file" >&2
121
- tail -n 40 "$log_file" >&2 || true
122
- rm -f "$pid_file"
123
- exit 1
124
- fi
125
-
126
- echo "started: $name (pid $pid)"
127
- }
128
-
129
- is_placeholder() {
130
- local value="$1"
131
- [[ -z "$value" ]] && return 0
132
- [[ "$value" == *"<fill-in:"* ]] && return 0
133
- [[ "$value" == *"<fill-in "* ]] && return 0
134
- [[ "$value" == "<64-char-lowercase-hex>" ]] && return 0
135
- [[ "$value" == "your-key" ]] && return 0
136
- return 1
137
- }
138
-
139
- load_env() {
140
- [[ -f "$ENV_FILE" ]] || {
141
- echo "ERROR: missing $ENV_FILE. Run: bash scripts/agent-playground-setup.sh init" >&2
142
- exit 1
143
- }
144
- # shellcheck disable=SC1090
145
- source "$ENV_FILE"
146
- }
147
-
148
- init_cmd() {
149
- local force=0
150
- if [[ "${1:-}" == "--force" ]]; then
151
- force=1
152
- elif [[ $# -gt 0 ]]; then
153
- echo "ERROR: unknown init option: $1" >&2
154
- usage
155
- exit 1
156
- fi
157
-
158
- if [[ -f "$ENV_FILE" && "$force" -ne 1 ]]; then
159
- echo "ERROR: $ENV_FILE already exists. Use init --force to regenerate." >&2
160
- exit 1
161
- fi
162
-
163
- ensure_dirs
164
-
165
- local job_token_secret
166
- local operator_secret_key
167
- job_token_secret="$(generate_hex_32)"
168
- operator_secret_key="$(generate_hex_32)"
169
-
170
- cat >"$ENV_FILE" <<EOF
171
- # NightPay agent playground environment
172
- # Generated by scripts/agent-playground-setup.sh on $(date -u +"%Y-%m-%dT%H:%M:%SZ")
173
-
174
- export MIDNIGHT_NETWORK="preprod"
175
- export MIP_PORT="8090"
176
- export UI_PORT="3333"
177
- export ENABLE_UI="1"
178
- export JOB_TOKEN_SECRET="${job_token_secret}"
179
- export OPERATOR_SECRET_KEY="${operator_secret_key}"
180
- export MASUMI_API_KEY="<fill-in: your ADMIN_KEY from Masumi .env>"
181
- export OPERATOR_ADDRESS="<fill-in: 64-char hex from bridge /operator-address>"
182
- export RECEIPT_CONTRACT_ADDRESS="<fill-in: 64-char hex from bridge /deploy>"
183
- export BRIDGE_URL="http://localhost:4000"
184
- export BRIDGE_ADMIN_TOKEN="<fill-in: deploy bearer token for bridge /deploy>"
185
- export ALLOW_LOCAL_URLS="1"
186
- EOF
187
-
188
- chmod 600 "$ENV_FILE" 2>/dev/null || true
189
- echo "created: $ENV_FILE"
190
- echo "next: edit MASUMI_API_KEY, OPERATOR_ADDRESS, RECEIPT_CONTRACT_ADDRESS, BRIDGE_URL"
191
- }
192
-
193
- start_cmd() {
194
- ensure_dirs
195
- load_env
196
-
197
- command -v bash >/dev/null 2>&1 || { echo "ERROR: bash not found in PATH" >&2; exit 1; }
198
- command -v node >/dev/null 2>&1 || { echo "ERROR: node not found in PATH" >&2; exit 1; }
199
- command -v npm >/dev/null 2>&1 || { echo "ERROR: npm not found in PATH" >&2; exit 1; }
200
-
201
- local mip_port="${MIP_PORT:-8090}"
202
- local ui_port="${UI_PORT:-3333}"
203
- local ui_enabled="${ENABLE_UI:-1}"
204
- local ui_package="${ROOT_DIR}/ui/package.json"
205
-
206
- start_process \
207
- "mip003-server" \
208
- "$MIP_PID_FILE" \
209
- "$MIP_LOG_FILE" \
210
- bash "$ROOT_DIR/skills/nightpay/scripts/mip003-server.sh" "$mip_port"
211
-
212
- if [[ "$ui_enabled" == "1" ]]; then
213
- if [[ -f "$ui_package" ]]; then
214
- start_process \
215
- "ui-dev-server" \
216
- "$UI_PID_FILE" \
217
- "$UI_LOG_FILE" \
218
- npm run dev --prefix "$ROOT_DIR/ui" -- --host 0.0.0.0 --port "$ui_port"
219
- else
220
- echo "WARN: ui/ missing at $ROOT_DIR/ui; skipping UI start (set ENABLE_UI=0 to silence)."
221
- rm -f "$UI_PID_FILE"
222
- fi
223
- else
224
- echo "UI start skipped (ENABLE_UI=$ui_enabled)."
225
- rm -f "$UI_PID_FILE"
226
- fi
227
-
228
- echo "logs:"
229
- echo " $MIP_LOG_FILE"
230
- if [[ "$ui_enabled" == "1" && -f "$ui_package" ]]; then
231
- echo " $UI_LOG_FILE"
232
- fi
233
- }
234
-
235
- stop_cmd() {
236
- stop_pid "ui-dev-server" "$UI_PID_FILE"
237
- stop_pid "mip003-server" "$MIP_PID_FILE"
238
- }
239
-
240
- status_cmd() {
241
- if is_pid_running "$MIP_PID_FILE"; then
242
- echo "mip003: running (pid $(cat "$MIP_PID_FILE"))"
243
- else
244
- echo "mip003: stopped"
245
- fi
246
- if is_pid_running "$UI_PID_FILE"; then
247
- echo "ui: running (pid $(cat "$UI_PID_FILE"))"
248
- else
249
- echo "ui: stopped"
250
- fi
251
- }
252
-
253
- doctor_cmd() {
254
- local failures=0
255
- local warnings=0
256
-
257
- pass() { echo "PASS: $1"; }
258
- fail() { echo "FAIL: $1"; failures=$((failures + 1)); }
259
- warn() { echo "WARN: $1"; warnings=$((warnings + 1)); }
260
-
261
- command -v bash >/dev/null 2>&1 && pass "tool: bash" || fail "tool: bash"
262
- command -v curl >/dev/null 2>&1 && pass "tool: curl" || fail "tool: curl"
263
- command -v node >/dev/null 2>&1 && pass "tool: node" || fail "tool: node"
264
- command -v npm >/dev/null 2>&1 && pass "tool: npm" || fail "tool: npm"
265
- detect_python && pass "tool: python3" || fail "tool: python3"
266
-
267
- if [[ -f "$ENV_FILE" ]]; then
268
- pass "env file present"
269
- load_env
270
- else
271
- fail "env file present"
272
- fi
273
-
274
- if [[ -f "$ENV_FILE" ]]; then
275
- is_placeholder "${JOB_TOKEN_SECRET:-}" && fail "JOB_TOKEN_SECRET" || pass "JOB_TOKEN_SECRET"
276
- is_placeholder "${OPERATOR_SECRET_KEY:-}" && fail "OPERATOR_SECRET_KEY" || pass "OPERATOR_SECRET_KEY"
277
- is_placeholder "${MASUMI_API_KEY:-}" && fail "MASUMI_API_KEY" || pass "MASUMI_API_KEY"
278
-
279
- local mip_port="${MIP_PORT:-8090}"
280
- local ui_port="${UI_PORT:-3333}"
281
- local ui_enabled="${ENABLE_UI:-1}"
282
- local ui_package="${ROOT_DIR}/ui/package.json"
283
- local code
284
-
285
- curl -fsS --max-time 5 "http://localhost:${mip_port}/availability" >/dev/null \
286
- && pass "MIP endpoint: /availability" || fail "MIP endpoint: /availability"
287
- curl -fsS --max-time 5 "http://localhost:${mip_port}/input_schema" >/dev/null \
288
- && pass "MIP endpoint: /input_schema" || fail "MIP endpoint: /input_schema"
289
- curl -fsS --max-time 5 "http://localhost:${mip_port}/ontology" >/dev/null \
290
- && pass "MIP endpoint: /ontology" || fail "MIP endpoint: /ontology"
291
-
292
- if [[ "$ui_enabled" != "1" ]]; then
293
- pass "UI endpoint: skipped (ENABLE_UI=$ui_enabled)"
294
- elif [[ ! -f "$ui_package" ]]; then
295
- warn "UI endpoint skipped (ui/ submodule missing)"
296
- else
297
- code="$(curl -sS -o /dev/null -w "%{http_code}" --max-time 5 "http://localhost:${ui_port}/" || echo "000")"
298
- if [[ "$code" == "200" ]]; then
299
- pass "UI endpoint: /"
300
- else
301
- fail "UI endpoint: /"
302
- fi
303
- fi
304
-
305
- curl -fsS --max-time 5 "http://localhost:3001/docs" >/dev/null \
306
- && pass "Masumi payment API" || warn "Masumi payment API"
307
- curl -fsS --max-time 5 "http://localhost:3000/docs" >/dev/null \
308
- && pass "Masumi registry API" || warn "Masumi registry API"
309
- fi
310
-
311
- if [[ "$failures" -gt 0 ]]; then
312
- echo "doctor result: FAIL (${failures} failures, ${warnings} warnings)"
313
- exit 1
314
- fi
315
-
316
- echo "doctor result: PASS (${warnings} warnings)"
317
- }
318
-
319
- ops_token_cmd() {
320
- load_env
321
- [[ -n "${OPERATOR_SECRET_KEY:-}" ]] || {
322
- echo "ERROR: OPERATOR_SECRET_KEY not set in $ENV_FILE" >&2
323
- exit 1
324
- }
325
- local minutes="${1:-15}"
326
- if ! [[ "$minutes" =~ ^[0-9]+$ ]] || [[ "$minutes" -lt 1 ]] || [[ "$minutes" -gt 1440 ]]; then
327
- echo "ERROR: minutes must be 1–1440 (default 15)" >&2
328
- exit 1
329
- fi
330
- detect_python || {
331
- echo "ERROR: python3/python required for ops-token" >&2
332
- exit 1
333
- }
334
- local token
335
- token="$("${PYTHON_CMD[@]}" - "$minutes" "$OPERATOR_SECRET_KEY" <<'PY'
336
- import hmac, hashlib, time, sys
337
- minutes = int(sys.argv[1])
338
- secret = sys.argv[2]
339
- expiry = int(time.time()) + 60 * minutes
340
- msg = f"ops:{expiry}"
341
- sig = hmac.new(secret.encode(), msg.encode(), hashlib.sha256).hexdigest()
342
- print(f"ops.{expiry}.{sig}")
343
- PY
344
- )"
345
- echo "$token"
346
- echo "" >&2
347
- echo "Paste the line above into the site at /ops (valid ${minutes} min). Do not share." >&2
348
- }
349
-
350
- main() {
351
- local cmd="${1:-}"
352
- case "$cmd" in
353
- init)
354
- shift
355
- init_cmd "$@"
356
- ;;
357
- start)
358
- start_cmd
359
- ;;
360
- stop)
361
- stop_cmd
362
- ;;
363
- doctor)
364
- doctor_cmd
365
- ;;
366
- status)
367
- status_cmd
368
- ;;
369
- ops-token)
370
- shift
371
- ops_token_cmd "${1:-15}"
372
- ;;
373
- -h|--help|help|"")
374
- usage
375
- ;;
376
- *)
377
- echo "ERROR: unknown command: $cmd" >&2
378
- usage
379
- exit 1
380
- ;;
381
- esac
382
- }
383
-
384
- main "$@"