@hasna/shortlinks 0.1.4 → 0.1.6

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
@@ -138,6 +138,17 @@ shortlinks cloud sync
138
138
 
139
139
  The cloud database service name is `shortlinks`.
140
140
 
141
+ ## AWS Origin
142
+
143
+ For an apex domain that needs stable A records, `infra/aws-ec2-user-data.sh` bootstraps a small EC2 redirect origin with:
144
+
145
+ - `@hasna/shortlinks` installed through Bun
146
+ - local SQLite data synced with the `shortlinks` RDS database through `@hasna/cloud`
147
+ - Caddy terminating HTTPS and proxying to `shortlinks serve`
148
+ - a systemd timer that syncs links and clicks every minute
149
+
150
+ The script reads the RDS password from AWS Secrets Manager through the instance role; it does not contain secret values.
151
+
141
152
  ## Development
142
153
 
143
154
  ```bash
package/dist/cli/index.js CHANGED
@@ -3435,13 +3435,6 @@ var PG_MIGRATIONS = [
3435
3435
  CREATE INDEX IF NOT EXISTS idx_clicks_domain ON clicks(domain_id);
3436
3436
  CREATE INDEX IF NOT EXISTS idx_clicks_clicked_at ON clicks(clicked_at);
3437
3437
  CREATE INDEX IF NOT EXISTS idx_clicks_updated ON clicks(updated_at);
3438
-
3439
- CREATE TABLE IF NOT EXISTS _pg_migrations (
3440
- id INTEGER PRIMARY KEY,
3441
- applied_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
3442
- );
3443
-
3444
- INSERT INTO _pg_migrations (id) VALUES (1) ON CONFLICT DO NOTHING;
3445
3438
  `
3446
3439
  ];
3447
3440
 
package/dist/index.js CHANGED
@@ -838,13 +838,6 @@ var PG_MIGRATIONS = [
838
838
  CREATE INDEX IF NOT EXISTS idx_clicks_domain ON clicks(domain_id);
839
839
  CREATE INDEX IF NOT EXISTS idx_clicks_clicked_at ON clicks(clicked_at);
840
840
  CREATE INDEX IF NOT EXISTS idx_clicks_updated ON clicks(updated_at);
841
-
842
- CREATE TABLE IF NOT EXISTS _pg_migrations (
843
- id INTEGER PRIMARY KEY,
844
- applied_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
845
- );
846
-
847
- INSERT INTO _pg_migrations (id) VALUES (1) ON CONFLICT DO NOTHING;
848
841
  `
849
842
  ];
850
843
  export {
@@ -0,0 +1,168 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ export AWS_REGION="${AWS_REGION:-us-east-1}"
5
+ export SHORTLINKS_HOME="/var/lib/shortlinks"
6
+ export SHORTLINKS_PACKAGE="@hasna/shortlinks@latest"
7
+ export RDS_SECRET_ID="rds!db-7a451ce6-83a9-40fa-b24a-81e5d5943511"
8
+ export RDS_HOST="hasnaxyz-prod-opensource.c4limg0qgqvk.us-east-1.rds.amazonaws.com"
9
+ export RDS_USERNAME="hasna_admin"
10
+
11
+ dnf update -y
12
+ dnf install -y awscli jq tar gzip shadow-utils libcap
13
+
14
+ if ! id shortlinks >/dev/null 2>&1; then
15
+ useradd --system --create-home --home-dir "${SHORTLINKS_HOME}" --shell /sbin/nologin shortlinks
16
+ fi
17
+
18
+ install -d -o shortlinks -g shortlinks "${SHORTLINKS_HOME}/.hasna/cloud"
19
+ install -d -o shortlinks -g shortlinks "${SHORTLINKS_HOME}/.hasna/shortlinks"
20
+
21
+ cat > "${SHORTLINKS_HOME}/.hasna/cloud/config.json" <<CLOUD_CONFIG
22
+ {
23
+ "rds": {
24
+ "host": "${RDS_HOST}",
25
+ "port": 5432,
26
+ "username": "${RDS_USERNAME}",
27
+ "password_env": "HASNA_RDS_PASSWORD",
28
+ "ssl": true
29
+ },
30
+ "mode": "hybrid",
31
+ "feedback_endpoint": "https://feedback.hasna.com/api/v1/feedback",
32
+ "auto_sync_interval_minutes": 0,
33
+ "sync": {
34
+ "schedule_minutes": 0
35
+ }
36
+ }
37
+ CLOUD_CONFIG
38
+ chown shortlinks:shortlinks "${SHORTLINKS_HOME}/.hasna/cloud/config.json"
39
+ chmod 600 "${SHORTLINKS_HOME}/.hasna/cloud/config.json"
40
+
41
+ su -s /bin/bash shortlinks -c 'curl -fsSL https://bun.sh/install | bash'
42
+ su -s /bin/bash shortlinks -c "${SHORTLINKS_HOME}/.bun/bin/bun install -g ${SHORTLINKS_PACKAGE} --no-cache"
43
+
44
+ cat > /usr/local/bin/shortlinks-env-exec <<'RUNNER'
45
+ #!/usr/bin/env bash
46
+ set -euo pipefail
47
+
48
+ export AWS_REGION="${AWS_REGION:-us-east-1}"
49
+ export HOME="/var/lib/shortlinks"
50
+ export PATH="/var/lib/shortlinks/.bun/bin:/usr/local/bin:/usr/bin:/bin"
51
+ export NODE_TLS_REJECT_UNAUTHORIZED="0"
52
+
53
+ secret_json="$(aws secretsmanager get-secret-value \
54
+ --region "${AWS_REGION}" \
55
+ --secret-id "rds!db-7a451ce6-83a9-40fa-b24a-81e5d5943511" \
56
+ --query SecretString \
57
+ --output text)"
58
+
59
+ export HASNA_RDS_PASSWORD
60
+ HASNA_RDS_PASSWORD="$(jq -r '.password' <<<"${secret_json}")"
61
+
62
+ exec "$@"
63
+ RUNNER
64
+ chmod 750 /usr/local/bin/shortlinks-env-exec
65
+ chown root:shortlinks /usr/local/bin/shortlinks-env-exec
66
+
67
+ su -s /bin/bash shortlinks -c '/usr/local/bin/shortlinks-env-exec shortlinks --json doctor'
68
+ su -s /bin/bash shortlinks -c '/usr/local/bin/shortlinks-env-exec shortlinks --json config set default-domain has.na'
69
+ su -s /bin/bash shortlinks -c '/usr/local/bin/shortlinks-env-exec shortlinks --json cloud pull --tables domains,links,clicks' || true
70
+
71
+ caddy_version="$(curl -fsSL https://api.github.com/repos/caddyserver/caddy/releases/latest | jq -r '.tag_name // "v2.10.2"' | sed 's/^v//')"
72
+ case "$(uname -m)" in
73
+ aarch64|arm64) caddy_arch="arm64" ;;
74
+ x86_64|amd64) caddy_arch="amd64" ;;
75
+ *) caddy_arch="arm64" ;;
76
+ esac
77
+ curl -fsSL -o /tmp/caddy.tar.gz "https://github.com/caddyserver/caddy/releases/download/v${caddy_version}/caddy_${caddy_version}_linux_${caddy_arch}.tar.gz"
78
+ tar -xzf /tmp/caddy.tar.gz -C /tmp caddy
79
+ install -m 0755 /tmp/caddy /usr/local/bin/caddy
80
+ setcap cap_net_bind_service=+ep /usr/local/bin/caddy || true
81
+
82
+ cat > /etc/systemd/system/shortlinks.service <<'SERVICE'
83
+ [Unit]
84
+ Description=Shortlinks redirect server
85
+ After=network-online.target
86
+ Wants=network-online.target
87
+
88
+ [Service]
89
+ Type=simple
90
+ User=shortlinks
91
+ Group=shortlinks
92
+ WorkingDirectory=/var/lib/shortlinks
93
+ Environment=HOME=/var/lib/shortlinks
94
+ Environment=PATH=/var/lib/shortlinks/.bun/bin:/usr/local/bin:/usr/bin:/bin
95
+ ExecStartPre=/usr/local/bin/shortlinks-env-exec shortlinks --json cloud pull --tables domains,links
96
+ ExecStart=/usr/local/bin/shortlinks-env-exec shortlinks serve --host 127.0.0.1 --port 8787 --default-host has.na
97
+ Restart=always
98
+ RestartSec=5
99
+
100
+ [Install]
101
+ WantedBy=multi-user.target
102
+ SERVICE
103
+
104
+ cat > /etc/systemd/system/shortlinks-sync.service <<'SERVICE'
105
+ [Unit]
106
+ Description=Sync shortlinks SQLite data with RDS
107
+ After=network-online.target
108
+ Wants=network-online.target
109
+
110
+ [Service]
111
+ Type=oneshot
112
+ User=shortlinks
113
+ Group=shortlinks
114
+ WorkingDirectory=/var/lib/shortlinks
115
+ Environment=HOME=/var/lib/shortlinks
116
+ Environment=PATH=/var/lib/shortlinks/.bun/bin:/usr/local/bin:/usr/bin:/bin
117
+ ExecStart=/usr/local/bin/shortlinks-env-exec shortlinks --json cloud sync --tables domains,links,clicks
118
+ SERVICE
119
+
120
+ cat > /etc/systemd/system/shortlinks-sync.timer <<'TIMER'
121
+ [Unit]
122
+ Description=Run shortlinks cloud sync every minute
123
+
124
+ [Timer]
125
+ OnBootSec=2min
126
+ OnUnitActiveSec=1min
127
+ Unit=shortlinks-sync.service
128
+
129
+ [Install]
130
+ WantedBy=timers.target
131
+ TIMER
132
+
133
+ cat > /etc/systemd/system/caddy.service <<'SERVICE'
134
+ [Unit]
135
+ Description=Caddy web server for shortlinks
136
+ After=network-online.target shortlinks.service
137
+ Wants=network-online.target
138
+
139
+ [Service]
140
+ Type=simple
141
+ User=root
142
+ Group=root
143
+ ExecStart=/usr/local/bin/caddy run --environ --config /etc/caddy/Caddyfile
144
+ ExecReload=/usr/local/bin/caddy reload --config /etc/caddy/Caddyfile --force
145
+ TimeoutStopSec=5s
146
+ LimitNOFILE=1048576
147
+ PrivateTmp=true
148
+ ProtectSystem=full
149
+ AmbientCapabilities=CAP_NET_BIND_SERVICE
150
+ Restart=on-failure
151
+
152
+ [Install]
153
+ WantedBy=multi-user.target
154
+ SERVICE
155
+
156
+ install -d /etc/caddy
157
+ cat > /etc/caddy/Caddyfile <<'CADDY'
158
+ has.na {
159
+ encode zstd gzip
160
+ reverse_proxy 127.0.0.1:8787
161
+ }
162
+ CADDY
163
+
164
+ systemctl daemon-reload
165
+ systemctl enable shortlinks.service shortlinks-sync.timer caddy.service
166
+ systemctl start shortlinks.service
167
+ systemctl start shortlinks-sync.timer
168
+ systemctl start caddy.service || true
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hasna/shortlinks",
3
- "version": "0.1.4",
3
+ "version": "0.1.6",
4
4
  "description": "CLI-only shortlink manager for custom domains, click tracking, Cloudflare setup, and @hasna cloud sync",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -25,6 +25,7 @@
25
25
  "files": [
26
26
  "dist",
27
27
  "cloudflare",
28
+ "infra",
28
29
  "LICENSE",
29
30
  "README.md",
30
31
  "SECURITY.md"