@hasna/shortlinks 0.1.10 → 0.1.11

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.
@@ -4,15 +4,9 @@ set -euo pipefail
4
4
  export AWS_REGION="${AWS_REGION:-us-east-1}"
5
5
  export SHORTLINKS_HOME="/var/lib/shortlinks"
6
6
  export SHORTLINKS_PACKAGE="@hasna/shortlinks@latest"
7
- export RDS_SECRET_ID="${RDS_SECRET_ID:-}"
8
- export RDS_HOST="${RDS_HOST:-}"
9
- export RDS_USERNAME="${RDS_USERNAME:-}"
10
- export SHORTLINKS_DOMAIN="${SHORTLINKS_DOMAIN:-}"
11
-
12
- : "${RDS_SECRET_ID:?Set RDS_SECRET_ID to the AWS Secrets Manager secret for the PostgreSQL password}"
13
- : "${RDS_HOST:?Set RDS_HOST to the PostgreSQL host}"
14
- : "${RDS_USERNAME:?Set RDS_USERNAME to the PostgreSQL username}"
15
- : "${SHORTLINKS_DOMAIN:?Set SHORTLINKS_DOMAIN to the public host served by Caddy}"
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"
16
10
 
17
11
  dnf update -y
18
12
  dnf install -y awscli jq tar gzip shadow-utils libcap
@@ -21,27 +15,28 @@ if ! id shortlinks >/dev/null 2>&1; then
21
15
  useradd --system --create-home --home-dir "${SHORTLINKS_HOME}" --shell /sbin/nologin shortlinks
22
16
  fi
23
17
 
24
- install -d -o shortlinks -g shortlinks "${SHORTLINKS_HOME}/.hasna/shortlinks/cloud"
18
+ install -d -o shortlinks -g shortlinks "${SHORTLINKS_HOME}/.hasna/cloud"
25
19
  install -d -o shortlinks -g shortlinks "${SHORTLINKS_HOME}/.hasna/shortlinks"
26
20
 
27
- cat > "${SHORTLINKS_HOME}/.hasna/shortlinks/cloud/config.json" <<CLOUD_CONFIG
21
+ cat > "${SHORTLINKS_HOME}/.hasna/cloud/config.json" <<CLOUD_CONFIG
28
22
  {
29
23
  "rds": {
30
24
  "host": "${RDS_HOST}",
31
25
  "port": 5432,
32
26
  "username": "${RDS_USERNAME}",
33
- "password_env": "SHORTLINKS_CLOUD_DATABASE_PASSWORD",
27
+ "password_env": "HASNA_RDS_PASSWORD",
34
28
  "ssl": true
35
29
  },
36
30
  "mode": "hybrid",
31
+ "feedback_endpoint": "https://feedback.hasna.com/api/v1/feedback",
37
32
  "auto_sync_interval_minutes": 0,
38
33
  "sync": {
39
34
  "schedule_minutes": 0
40
35
  }
41
36
  }
42
37
  CLOUD_CONFIG
43
- chown shortlinks:shortlinks "${SHORTLINKS_HOME}/.hasna/shortlinks/cloud/config.json"
44
- chmod 600 "${SHORTLINKS_HOME}/.hasna/shortlinks/cloud/config.json"
38
+ chown shortlinks:shortlinks "${SHORTLINKS_HOME}/.hasna/cloud/config.json"
39
+ chmod 600 "${SHORTLINKS_HOME}/.hasna/cloud/config.json"
45
40
 
46
41
  su -s /bin/bash shortlinks -c 'curl -fsSL https://bun.sh/install | bash'
47
42
  su -s /bin/bash shortlinks -c "${SHORTLINKS_HOME}/.bun/bin/bun install -g ${SHORTLINKS_PACKAGE} --no-cache"
@@ -55,16 +50,14 @@ export HOME="/var/lib/shortlinks"
55
50
  export PATH="/var/lib/shortlinks/.bun/bin:/usr/local/bin:/usr/bin:/bin"
56
51
  export NODE_TLS_REJECT_UNAUTHORIZED="0"
57
52
 
58
- : "${RDS_SECRET_ID:?Set RDS_SECRET_ID to the AWS Secrets Manager secret for the PostgreSQL password}"
59
-
60
53
  secret_json="$(aws secretsmanager get-secret-value \
61
54
  --region "${AWS_REGION}" \
62
- --secret-id "${RDS_SECRET_ID}" \
55
+ --secret-id "rds!db-7a451ce6-83a9-40fa-b24a-81e5d5943511" \
63
56
  --query SecretString \
64
57
  --output text)"
65
58
 
66
- export SHORTLINKS_CLOUD_DATABASE_PASSWORD
67
- SHORTLINKS_CLOUD_DATABASE_PASSWORD="$(jq -r '.password' <<<"${secret_json}")"
59
+ export HASNA_RDS_PASSWORD
60
+ HASNA_RDS_PASSWORD="$(jq -r '.password' <<<"${secret_json}")"
68
61
 
69
62
  exec "$@"
70
63
  RUNNER
@@ -73,15 +66,6 @@ chown root:shortlinks /usr/local/bin/shortlinks-env-exec
73
66
 
74
67
  su -s /bin/bash shortlinks -c 'PATH=/var/lib/shortlinks/.bun/bin:$PATH shortlinks --version'
75
68
 
76
- cat > /etc/default/shortlinks <<SHORTLINKS_ENV
77
- AWS_REGION=${AWS_REGION}
78
- RDS_SECRET_ID=${RDS_SECRET_ID}
79
- SHORTLINKS_DOMAIN=${SHORTLINKS_DOMAIN}
80
- SHORTLINKS_STORE=cloud
81
- SHORTLINKS_ENV
82
- chmod 640 /etc/default/shortlinks
83
- chown root:shortlinks /etc/default/shortlinks
84
-
85
69
  caddy_version="$(curl -fsSL https://api.github.com/repos/caddyserver/caddy/releases/latest | jq -r '.tag_name // "v2.10.2"' | sed 's/^v//')"
86
70
  case "$(uname -m)" in
87
71
  aarch64|arm64) caddy_arch="arm64" ;;
@@ -106,8 +90,8 @@ Group=shortlinks
106
90
  WorkingDirectory=/var/lib/shortlinks
107
91
  Environment=HOME=/var/lib/shortlinks
108
92
  Environment=PATH=/var/lib/shortlinks/.bun/bin:/usr/local/bin:/usr/bin:/bin
109
- EnvironmentFile=/etc/default/shortlinks
110
- ExecStart=/usr/local/bin/shortlinks-env-exec shortlinks serve --cloud --host 127.0.0.1 --port 8787 --default-host ${SHORTLINKS_DOMAIN}
93
+ Environment=SHORTLINKS_STORE=cloud
94
+ ExecStart=/usr/local/bin/shortlinks-env-exec shortlinks serve --cloud --host 127.0.0.1 --port 8787 --default-host has.na
111
95
  Restart=always
112
96
  RestartSec=5
113
97
 
@@ -139,8 +123,8 @@ WantedBy=multi-user.target
139
123
  SERVICE
140
124
 
141
125
  install -d /etc/caddy
142
- cat > /etc/caddy/Caddyfile <<CADDY
143
- ${SHORTLINKS_DOMAIN} {
126
+ cat > /etc/caddy/Caddyfile <<'CADDY'
127
+ has.na {
144
128
  encode zstd gzip
145
129
  reverse_proxy 127.0.0.1:8787
146
130
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@hasna/shortlinks",
3
- "version": "0.1.10",
4
- "description": "CLI-only shortlink manager for custom domains, click tracking, Cloudflare setup, and repo-native cloud sync",
3
+ "version": "0.1.11",
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",
7
7
  "types": "dist/index.d.ts",
@@ -31,7 +31,7 @@
31
31
  "SECURITY.md"
32
32
  ],
33
33
  "scripts": {
34
- "build": "rm -rf dist && bun build src/cli/index.ts --outdir dist/cli --target bun && bun build src/index.ts --outdir dist --target bun && bun build src/server.ts --outdir dist --target bun && bun build src/cloudflare.ts --outdir dist --target bun && tsc -p tsconfig.build.json --emitDeclarationOnly --outDir dist",
34
+ "build": "rm -rf dist && bun build src/cli/index.ts --outdir dist/cli --target bun --external @hasna/cloud && bun build src/index.ts --outdir dist --target bun --external @hasna/cloud && bun build src/server.ts --outdir dist --target bun --external @hasna/cloud && bun build src/cloudflare.ts --outdir dist --target bun && tsc -p tsconfig.build.json --emitDeclarationOnly --outDir dist",
35
35
  "typecheck": "tsc --noEmit",
36
36
  "test": "bun test",
37
37
  "dev:cli": "bun run src/cli/index.ts",
@@ -66,13 +66,13 @@
66
66
  "author": "Andrei Hasna <andrei@hasna.com>",
67
67
  "license": "Apache-2.0",
68
68
  "dependencies": {
69
+ "@hasna/cloud": "0.1.30",
70
+ "@hasna/events": "^0.1.6",
69
71
  "chalk": "^5.4.1",
70
- "commander": "^13.1.0",
71
- "pg": "^8.13.3"
72
+ "commander": "^13.1.0"
72
73
  },
73
74
  "devDependencies": {
74
75
  "@types/bun": "^1.2.4",
75
- "@types/pg": "^8.11.11",
76
76
  "typescript": "^5.7.3"
77
77
  }
78
78
  }
@@ -1,13 +0,0 @@
1
- export type CloudMode = "local" | "hybrid" | "cloud";
2
- export interface CloudConfig {
3
- mode: CloudMode;
4
- rds: {
5
- host: string;
6
- port: number;
7
- username: string;
8
- password_env: string;
9
- ssl: boolean;
10
- };
11
- }
12
- export declare function getCloudConfig(): CloudConfig;
13
- export declare function getConnectionString(dbName?: string): string;
@@ -1,28 +0,0 @@
1
- import { PgAdapterAsync } from "./remote-storage.js";
2
- export interface SyncResult {
3
- table: string;
4
- direction: "push" | "pull";
5
- rowsRead: number;
6
- rowsWritten: number;
7
- errors: string[];
8
- }
9
- export interface CloudStatus {
10
- mode: string;
11
- enabled: boolean;
12
- db_path: string;
13
- tables: Array<{
14
- table: string;
15
- rows: number;
16
- }>;
17
- }
18
- export declare const CLOUD_TABLES: readonly ["domains", "links", "clicks"];
19
- export declare function getCloudPg(): Promise<PgAdapterAsync>;
20
- export declare function runCloudMigrations(remote: PgAdapterAsync): Promise<void>;
21
- export declare function getCloudStatus(dbPath?: string): CloudStatus;
22
- export declare function pushCloudChanges(dbPath?: string, tables?: string[]): Promise<SyncResult[]>;
23
- export declare function pullCloudChanges(dbPath?: string, tables?: string[]): Promise<SyncResult[]>;
24
- export declare function syncCloudChanges(dbPath?: string, tables?: string[]): Promise<{
25
- push: SyncResult[];
26
- pull: SyncResult[];
27
- }>;
28
- export declare function parseCloudTables(raw?: string): string[];
@@ -1,7 +0,0 @@
1
- export interface PgMigrationResult {
2
- applied: number[];
3
- alreadyApplied: number[];
4
- errors: string[];
5
- totalMigrations: number;
6
- }
7
- export declare function applyPgMigrations(connectionString: string): Promise<PgMigrationResult>;
@@ -1,11 +0,0 @@
1
- export declare class PgAdapterAsync {
2
- private readonly pool;
3
- constructor(connectionString: string);
4
- run(sql: string, ...params: unknown[]): Promise<{
5
- changes: number;
6
- }>;
7
- get(sql: string, ...params: unknown[]): Promise<unknown>;
8
- all(sql: string, ...params: unknown[]): Promise<unknown[]>;
9
- exec(sql: string): Promise<void>;
10
- close(): Promise<void>;
11
- }