@hasna/shortlinks 0.2.7 → 0.2.10

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.
@@ -1,4 +1,6 @@
1
1
  import type { AddDomainInput, Click, ClickInput, CreateLinkInput, Domain, Link, LinkStats } from "./types.js";
2
+ /** Plain env shape consumed by the store resolver (own-property reads only). */
3
+ export type Env = Record<string, string | undefined>;
2
4
  export interface ListLinksOptions {
3
5
  domain?: string;
4
6
  activeOnly?: boolean;
@@ -11,11 +13,11 @@ export interface TotalStats {
11
13
  }
12
14
  /**
13
15
  * The single storage surface shared by LocalStore and ApiStore. All methods are
14
- * async so one call site works against either transport with no mode branching.
16
+ * async so one call site works against either transport.
15
17
  */
16
18
  export interface Store {
17
19
  /** Which transport backs this store (for banners/diagnostics only). */
18
- readonly kind: "local" | "cloud-http";
20
+ readonly kind: "local" | "http";
19
21
  addDomain(input: AddDomainInput): Promise<Domain>;
20
22
  listDomains(): Promise<Domain[]>;
21
23
  getDomain(hostnameOrId: string): Promise<Domain | null>;
@@ -14,10 +14,13 @@ if ! id shortlinks >/dev/null 2>&1; then
14
14
  fi
15
15
 
16
16
  install -d -o shortlinks -g shortlinks "${SHORTLINKS_HOME}/.hasna/shortlinks"
17
+ # The server data backend is selected by HASNA_SHORTLINKS_DATABASE_URL (exported
18
+ # by shortlinks-env-exec below); unset selects the on-box SQLite store. The
19
+ # sanctioned PostgreSQL service entrypoint is `shortlinks-serve` (see
20
+ # Dockerfile) — this unit runs the client-side redirect server, which resolves
21
+ # its store from the client env contract (on-box SQLite or the hosted /v1 API).
17
22
  cat > /etc/shortlinks.env <<ENV
18
23
  SHORTLINKS_DATABASE_SECRET_ID=${SHORTLINKS_DATABASE_SECRET_ID}
19
- HASNA_SHORTLINKS_STORE=postgres
20
- HASNA_SHORTLINKS_DATABASE_SSL=true
21
24
  ENV
22
25
  chown root:shortlinks /etc/shortlinks.env
23
26
  chmod 640 /etc/shortlinks.env
@@ -32,8 +35,6 @@ set -euo pipefail
32
35
  export AWS_REGION="${AWS_REGION:-us-east-1}"
33
36
  export HOME="/var/lib/shortlinks"
34
37
  export PATH="/var/lib/shortlinks/.bun/bin:/usr/local/bin:/usr/bin:/bin"
35
- export HASNA_SHORTLINKS_STORE="postgres"
36
- export HASNA_SHORTLINKS_DATABASE_SSL="${HASNA_SHORTLINKS_DATABASE_SSL:-true}"
37
38
 
38
39
  secret_json="$(aws secretsmanager get-secret-value \
39
40
  --region "${AWS_REGION}" \
@@ -91,8 +92,7 @@ WorkingDirectory=/var/lib/shortlinks
91
92
  Environment=HOME=/var/lib/shortlinks
92
93
  Environment=PATH=/var/lib/shortlinks/.bun/bin:/usr/local/bin:/usr/bin:/bin
93
94
  EnvironmentFile=/etc/shortlinks.env
94
- ExecStartPre=/usr/local/bin/shortlinks-env-exec shortlinks postgres migrate
95
- ExecStart=/usr/local/bin/shortlinks-env-exec shortlinks --store postgres serve --host 127.0.0.1 --port 8787 --default-host has.na
95
+ ExecStart=/usr/local/bin/shortlinks-env-exec shortlinks serve --host 127.0.0.1 --port 8787 --default-host has.na
96
96
  Restart=always
97
97
  RestartSec=5
98
98
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@hasna/shortlinks",
3
- "version": "0.2.7",
4
- "description": "Shortlink manager for custom domains and click tracking, with local SQLite or self-hosted cloud (/v1 API + bearer key) storage and Cloudflare setup helpers",
3
+ "version": "0.2.10",
4
+ "description": "Shortlink manager for custom domains and click tracking, with local SQLite or hosted /v1 API (bearer key) storage and Cloudflare setup helpers",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
7
7
  "types": "dist/index.d.ts",
@@ -41,15 +41,18 @@
41
41
  "SECURITY.md"
42
42
  ],
43
43
  "scripts": {
44
- "build": "rm -rf dist && bun build src/cli/index.ts src/mcp/index.ts src/serve/index.ts src/sdk/index.ts src/index.ts src/server.ts src/cloudflare.ts src/pg-store.ts --root src --outdir dist --target bun --external @modelcontextprotocol/sdk && tsc -p tsconfig.build.json --emitDeclarationOnly --outDir dist",
44
+ "build": "rm -rf dist && bun build src/cli/index.ts src/mcp/index.ts src/serve/index.ts src/sdk/index.ts src/index.ts src/server.ts src/cloudflare.ts src/pg-store.ts --root src --outdir dist --target bun --external @modelcontextprotocol/sdk --external pg && tsc -p tsconfig.build.json --emitDeclarationOnly --outDir dist",
45
45
  "sdk:generate": "bun run scripts/generate-sdk.ts",
46
46
  "typecheck": "tsc --noEmit",
47
47
  "test": "bun test",
48
+ "test:pg": "bun scripts/pg-test-gate.ts",
49
+ "scan:artifact": "bun scripts/scan-artifact.ts",
48
50
  "dev:cli": "bun run src/cli/index.ts",
49
51
  "dev:mcp": "bun run src/mcp/index.ts",
50
52
  "dev:serve": "bun run src/serve/index.ts",
51
53
  "verify:release": "bun run typecheck && bun run test && bun run build",
52
- "prepublishOnly": "bun run verify:release"
54
+ "prepublishOnly": "bun run verify:release",
55
+ "prepack": "bun run build && bun run scan:artifact"
53
56
  },
54
57
  "keywords": [
55
58
  "shortlinks",
@@ -88,7 +91,7 @@
88
91
  "pg": "^8.13.3"
89
92
  },
90
93
  "devDependencies": {
91
- "@hasna/contracts": "^0.5.2",
94
+ "@hasna/contracts": "0.13.1",
92
95
  "@types/pg": "^8.11.11",
93
96
  "@types/bun": "^1.2.4",
94
97
  "typescript": "^5.7.3"
@@ -1,47 +0,0 @@
1
- export declare const STORAGE_MODES: readonly ["local", "cloud"];
2
- export type StorageMode = (typeof STORAGE_MODES)[number];
3
- export declare const DEPRECATED_STORAGE_MODE_ALIASES: readonly ["remote", "hybrid", "self_hosted"];
4
- export type Env = Record<string, string | undefined>;
5
- export interface StorageModeNormalization {
6
- mode: StorageMode;
7
- /** The deprecated alias that was normalized to `cloud`, if any. */
8
- deprecatedAlias: string | null;
9
- }
10
- /**
11
- * Normalize a raw storage-mode string to the `local | cloud` runtime enum.
12
- * Accepts deprecated aliases (`remote`, `hybrid`, `self_hosted`) and maps them
13
- * to `cloud`. Throws on any other value.
14
- */
15
- export declare function normalizeStorageMode(value: string): StorageModeNormalization;
16
- /** Upper-snake env token for an app name, e.g. `todos` -> `TODOS`. */
17
- export declare function envToken(name: string): string;
18
- export interface StorageEnvKeys {
19
- /** `HASNA_<NAME>_STORAGE_MODE` then the optional `<NAME>_STORAGE_MODE` alias. */
20
- modeKeys: string[];
21
- /** `HASNA_<NAME>_DATABASE_URL` then the optional `<NAME>_DATABASE_URL` alias. */
22
- databaseUrlKeys: string[];
23
- }
24
- /** Resolve the canonical env-key spec for an app's storage config. */
25
- export declare function storageEnvKeys(name: string): StorageEnvKeys;
26
- export interface StorageModeResolution {
27
- mode: StorageMode;
28
- /** Env key the mode came from, or `"default"`. */
29
- source: string;
30
- deprecatedAlias: string | null;
31
- databaseUrlPresent: boolean;
32
- /** Env key the database URL came from, or `null`. */
33
- databaseUrlSource: string | null;
34
- warning: string | null;
35
- }
36
- /**
37
- * Resolve an app's storage mode from the environment per the contract env spec.
38
- * Precedence: `HASNA_<NAME>_STORAGE_MODE`, then `<NAME>_STORAGE_MODE`, else
39
- * `local`. Never reads secret values — only detects DATABASE_URL presence.
40
- */
41
- export declare function resolveStorageMode(name: string, env?: Env): StorageModeResolution;
42
- /**
43
- * Resolve the database URL value for an app, honoring the canonical then alias
44
- * env keys. Returns `null` when unset. The caller is responsible for never
45
- * logging the returned value.
46
- */
47
- export declare function resolveDatabaseUrl(name: string, env?: Env): string | null;