@hasna/shortlinks 0.1.22 → 0.1.24
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 +40 -20
- package/dist/cli/index.js +2507 -2019
- package/dist/cloudflare.js +141 -4
- package/dist/db/migrations.d.ts +20 -0
- package/dist/generated/storage-kit/health.d.ts +19 -0
- package/dist/generated/storage-kit/index.d.ts +7 -0
- package/dist/generated/storage-kit/migrations.d.ts +47 -0
- package/dist/generated/storage-kit/mode.d.ts +47 -0
- package/dist/generated/storage-kit/pool.d.ts +33 -0
- package/dist/generated/storage-kit/query.d.ts +35 -0
- package/dist/generated/storage-kit/tls.d.ts +25 -0
- package/dist/index.d.ts +6 -1
- package/dist/index.js +3139 -232
- package/dist/mcp/http.d.ts +16 -0
- package/dist/mcp/index.d.ts +14 -0
- package/dist/mcp/index.js +1493 -0
- package/dist/pg-store.d.ts +20 -2
- package/dist/pg-store.js +913 -0
- package/dist/runtime.d.ts +65 -0
- package/dist/runtime.js +214 -0
- package/dist/sdk/generated.d.ts +178 -0
- package/dist/sdk/index.d.ts +12 -0
- package/dist/sdk/index.js +500 -0
- package/dist/serve/app.d.ts +21 -0
- package/dist/serve/index.d.ts +14 -0
- package/dist/serve/index.js +8817 -0
- package/dist/serve/openapi.d.ts +8 -0
- package/dist/server.js +33 -0
- package/infra/aws-ec2-user-data.sh +32 -31
- package/package.json +29 -7
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
export type ShortlinksStoreMode = "local" | "postgres";
|
|
2
|
+
export type ShortlinksRuntimeEnv = Record<string, string | undefined>;
|
|
3
|
+
export interface ShortlinksPostgresConfig {
|
|
4
|
+
provider: "postgres";
|
|
5
|
+
url: string;
|
|
6
|
+
ssl: boolean;
|
|
7
|
+
}
|
|
8
|
+
export interface ShortlinksRuntimeConfig {
|
|
9
|
+
service: "shortlinks";
|
|
10
|
+
mode: ShortlinksStoreMode;
|
|
11
|
+
database?: ShortlinksPostgresConfig;
|
|
12
|
+
}
|
|
13
|
+
export declare const SHORTLINKS_RUNTIME_ENV: {
|
|
14
|
+
readonly store: "HASNA_SHORTLINKS_STORE";
|
|
15
|
+
readonly databaseUrl: "HASNA_SHORTLINKS_DATABASE_URL";
|
|
16
|
+
readonly databaseSsl: "HASNA_SHORTLINKS_DATABASE_SSL";
|
|
17
|
+
};
|
|
18
|
+
export declare const SHORTLINKS_RUNTIME_FALLBACK_ENV: {
|
|
19
|
+
readonly store: "SHORTLINKS_STORE";
|
|
20
|
+
readonly databaseUrl: "SHORTLINKS_DATABASE_URL";
|
|
21
|
+
readonly databaseSsl: "SHORTLINKS_DATABASE_SSL";
|
|
22
|
+
};
|
|
23
|
+
export declare const CANONICAL_SHORTLINKS_POSTGRES_CLUSTER = "hasna-xyz-infra-apps-prod-postgres";
|
|
24
|
+
export declare const CANONICAL_SHORTLINKS_POSTGRES_DATABASE = "shortlinks";
|
|
25
|
+
export declare const CANONICAL_SHORTLINKS_RUNTIME_SECRET_PATH = "hasna/xyz/opensource/shortlinks/prod/postgres";
|
|
26
|
+
export interface CanonicalShortlinksPostgresConfig {
|
|
27
|
+
cluster: typeof CANONICAL_SHORTLINKS_POSTGRES_CLUSTER;
|
|
28
|
+
database: typeof CANONICAL_SHORTLINKS_POSTGRES_DATABASE;
|
|
29
|
+
runtimeSecretPath: typeof CANONICAL_SHORTLINKS_RUNTIME_SECRET_PATH;
|
|
30
|
+
primaryEnv: typeof SHORTLINKS_RUNTIME_ENV.databaseUrl;
|
|
31
|
+
fallbackEnv: typeof SHORTLINKS_RUNTIME_FALLBACK_ENV.databaseUrl;
|
|
32
|
+
}
|
|
33
|
+
export interface RuntimeEnvStatus {
|
|
34
|
+
name: string;
|
|
35
|
+
active_name: string;
|
|
36
|
+
configured: boolean;
|
|
37
|
+
}
|
|
38
|
+
export interface ShortlinksRuntimeStatus {
|
|
39
|
+
ok: boolean;
|
|
40
|
+
service: "shortlinks";
|
|
41
|
+
mode: ShortlinksStoreMode;
|
|
42
|
+
local_default: boolean;
|
|
43
|
+
postgres_enabled: boolean;
|
|
44
|
+
database: {
|
|
45
|
+
configured: boolean;
|
|
46
|
+
provider: "postgres" | null;
|
|
47
|
+
redacted_url: string | null;
|
|
48
|
+
ssl: boolean | null;
|
|
49
|
+
};
|
|
50
|
+
env: Record<keyof typeof SHORTLINKS_RUNTIME_ENV, RuntimeEnvStatus>;
|
|
51
|
+
canonical: CanonicalShortlinksPostgresConfig;
|
|
52
|
+
issues: string[];
|
|
53
|
+
warnings: string[];
|
|
54
|
+
no_network: true;
|
|
55
|
+
}
|
|
56
|
+
export declare function getCanonicalShortlinksPostgresConfig(): CanonicalShortlinksPostgresConfig;
|
|
57
|
+
export declare function parseShortlinksStoreMode(value: string | undefined): ShortlinksStoreMode;
|
|
58
|
+
export declare function getShortlinksStoreMode(env?: ShortlinksRuntimeEnv): ShortlinksStoreMode;
|
|
59
|
+
export declare function getShortlinksDatabaseUrl(env?: ShortlinksRuntimeEnv): string | undefined;
|
|
60
|
+
export declare function getShortlinksDatabaseSsl(env?: ShortlinksRuntimeEnv): boolean;
|
|
61
|
+
export declare function getShortlinksRuntimeEnvName(env: ShortlinksRuntimeEnv, key: keyof typeof SHORTLINKS_RUNTIME_ENV): string;
|
|
62
|
+
export declare function loadShortlinksRuntimeConfig(env?: ShortlinksRuntimeEnv): ShortlinksRuntimeConfig;
|
|
63
|
+
export declare function assertShortlinksPostgresConfig(config: ShortlinksRuntimeConfig): void;
|
|
64
|
+
export declare function getShortlinksRuntimeStatus(env?: ShortlinksRuntimeEnv): ShortlinksRuntimeStatus;
|
|
65
|
+
export declare function redactDatabaseUrl(value: string | undefined): string | null;
|
package/dist/runtime.js
ADDED
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
function __accessProp(key) {
|
|
8
|
+
return this[key];
|
|
9
|
+
}
|
|
10
|
+
var __toESMCache_node;
|
|
11
|
+
var __toESMCache_esm;
|
|
12
|
+
var __toESM = (mod, isNodeMode, target) => {
|
|
13
|
+
var canCache = mod != null && typeof mod === "object";
|
|
14
|
+
if (canCache) {
|
|
15
|
+
var cache = isNodeMode ? __toESMCache_node ??= new WeakMap : __toESMCache_esm ??= new WeakMap;
|
|
16
|
+
var cached = cache.get(mod);
|
|
17
|
+
if (cached)
|
|
18
|
+
return cached;
|
|
19
|
+
}
|
|
20
|
+
target = mod != null ? __create(__getProtoOf(mod)) : {};
|
|
21
|
+
const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
|
|
22
|
+
for (let key of __getOwnPropNames(mod))
|
|
23
|
+
if (!__hasOwnProp.call(to, key))
|
|
24
|
+
__defProp(to, key, {
|
|
25
|
+
get: __accessProp.bind(mod, key),
|
|
26
|
+
enumerable: true
|
|
27
|
+
});
|
|
28
|
+
if (canCache)
|
|
29
|
+
cache.set(mod, to);
|
|
30
|
+
return to;
|
|
31
|
+
};
|
|
32
|
+
var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
|
|
33
|
+
var __require = import.meta.require;
|
|
34
|
+
|
|
35
|
+
// src/runtime.ts
|
|
36
|
+
var SHORTLINKS_RUNTIME_ENV = {
|
|
37
|
+
store: "HASNA_SHORTLINKS_STORE",
|
|
38
|
+
databaseUrl: "HASNA_SHORTLINKS_DATABASE_URL",
|
|
39
|
+
databaseSsl: "HASNA_SHORTLINKS_DATABASE_SSL"
|
|
40
|
+
};
|
|
41
|
+
var SHORTLINKS_RUNTIME_FALLBACK_ENV = {
|
|
42
|
+
store: "SHORTLINKS_STORE",
|
|
43
|
+
databaseUrl: "SHORTLINKS_DATABASE_URL",
|
|
44
|
+
databaseSsl: "SHORTLINKS_DATABASE_SSL"
|
|
45
|
+
};
|
|
46
|
+
var CANONICAL_SHORTLINKS_POSTGRES_CLUSTER = "hasna-xyz-infra-apps-prod-postgres";
|
|
47
|
+
var CANONICAL_SHORTLINKS_POSTGRES_DATABASE = "shortlinks";
|
|
48
|
+
var CANONICAL_SHORTLINKS_RUNTIME_SECRET_PATH = "hasna/xyz/opensource/shortlinks/prod/postgres";
|
|
49
|
+
function getCanonicalShortlinksPostgresConfig() {
|
|
50
|
+
return {
|
|
51
|
+
cluster: CANONICAL_SHORTLINKS_POSTGRES_CLUSTER,
|
|
52
|
+
database: CANONICAL_SHORTLINKS_POSTGRES_DATABASE,
|
|
53
|
+
runtimeSecretPath: CANONICAL_SHORTLINKS_RUNTIME_SECRET_PATH,
|
|
54
|
+
primaryEnv: SHORTLINKS_RUNTIME_ENV.databaseUrl,
|
|
55
|
+
fallbackEnv: SHORTLINKS_RUNTIME_FALLBACK_ENV.databaseUrl
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
function parseShortlinksStoreMode(value) {
|
|
59
|
+
const normalized = clean(value)?.toLowerCase();
|
|
60
|
+
if (!normalized)
|
|
61
|
+
return "local";
|
|
62
|
+
if (normalized === "local" || normalized === "postgres")
|
|
63
|
+
return normalized;
|
|
64
|
+
if (normalized === "pg")
|
|
65
|
+
return "postgres";
|
|
66
|
+
throw new Error(`${SHORTLINKS_RUNTIME_ENV.store} must be local or postgres`);
|
|
67
|
+
}
|
|
68
|
+
function getShortlinksStoreMode(env = process.env) {
|
|
69
|
+
return parseShortlinksStoreMode(readRuntimeEnv(env, "store").value);
|
|
70
|
+
}
|
|
71
|
+
function getShortlinksDatabaseUrl(env = process.env) {
|
|
72
|
+
return readRuntimeEnv(env, "databaseUrl").value;
|
|
73
|
+
}
|
|
74
|
+
function getShortlinksDatabaseSsl(env = process.env) {
|
|
75
|
+
return parseBoolean(readRuntimeEnv(env, "databaseSsl").value, true);
|
|
76
|
+
}
|
|
77
|
+
function getShortlinksRuntimeEnvName(env, key) {
|
|
78
|
+
const primary = SHORTLINKS_RUNTIME_ENV[key];
|
|
79
|
+
if (clean(env[primary]))
|
|
80
|
+
return primary;
|
|
81
|
+
return SHORTLINKS_RUNTIME_FALLBACK_ENV[key];
|
|
82
|
+
}
|
|
83
|
+
function loadShortlinksRuntimeConfig(env = process.env) {
|
|
84
|
+
const mode = getShortlinksStoreMode(env);
|
|
85
|
+
const databaseUrl = getShortlinksDatabaseUrl(env);
|
|
86
|
+
return {
|
|
87
|
+
service: "shortlinks",
|
|
88
|
+
mode,
|
|
89
|
+
...databaseUrl ? {
|
|
90
|
+
database: {
|
|
91
|
+
provider: "postgres",
|
|
92
|
+
url: databaseUrl,
|
|
93
|
+
ssl: getShortlinksDatabaseSsl(env)
|
|
94
|
+
}
|
|
95
|
+
} : {}
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
function assertShortlinksPostgresConfig(config) {
|
|
99
|
+
if (config.mode !== "postgres")
|
|
100
|
+
return;
|
|
101
|
+
if (!config.database?.url) {
|
|
102
|
+
throw new Error(`${SHORTLINKS_RUNTIME_ENV.databaseUrl} is required when ${SHORTLINKS_RUNTIME_ENV.store}=postgres`);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
function getShortlinksRuntimeStatus(env = process.env) {
|
|
106
|
+
const issues = [];
|
|
107
|
+
const warnings = [];
|
|
108
|
+
let config;
|
|
109
|
+
try {
|
|
110
|
+
config = loadShortlinksRuntimeConfig(env);
|
|
111
|
+
} catch (error) {
|
|
112
|
+
issues.push(error instanceof Error ? error.message : String(error));
|
|
113
|
+
config = { service: "shortlinks", mode: "local" };
|
|
114
|
+
}
|
|
115
|
+
try {
|
|
116
|
+
assertShortlinksPostgresConfig(config);
|
|
117
|
+
} catch (error) {
|
|
118
|
+
issues.push(error instanceof Error ? error.message : String(error));
|
|
119
|
+
}
|
|
120
|
+
if (config.mode === "local" && config.database?.url) {
|
|
121
|
+
warnings.push(`${SHORTLINKS_RUNTIME_ENV.store}=local ignores configured Postgres database settings`);
|
|
122
|
+
}
|
|
123
|
+
return {
|
|
124
|
+
ok: issues.length === 0,
|
|
125
|
+
service: "shortlinks",
|
|
126
|
+
mode: config.mode,
|
|
127
|
+
local_default: config.mode === "local",
|
|
128
|
+
postgres_enabled: config.mode === "postgres",
|
|
129
|
+
database: {
|
|
130
|
+
configured: Boolean(config.database?.url),
|
|
131
|
+
provider: config.database?.provider ?? null,
|
|
132
|
+
redacted_url: redactDatabaseUrl(config.database?.url),
|
|
133
|
+
ssl: config.database?.ssl ?? null
|
|
134
|
+
},
|
|
135
|
+
env: runtimeEnvStatus(env),
|
|
136
|
+
canonical: getCanonicalShortlinksPostgresConfig(),
|
|
137
|
+
issues,
|
|
138
|
+
warnings,
|
|
139
|
+
no_network: true
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
function redactDatabaseUrl(value) {
|
|
143
|
+
if (!value)
|
|
144
|
+
return null;
|
|
145
|
+
try {
|
|
146
|
+
const url = new URL(value);
|
|
147
|
+
if (url.username)
|
|
148
|
+
url.username = "***";
|
|
149
|
+
if (url.password)
|
|
150
|
+
url.password = "***";
|
|
151
|
+
for (const key of Array.from(url.searchParams.keys())) {
|
|
152
|
+
if (isSensitiveQueryKey(key))
|
|
153
|
+
url.searchParams.set(key, "***");
|
|
154
|
+
}
|
|
155
|
+
return url.toString();
|
|
156
|
+
} catch {
|
|
157
|
+
return "(redacted)";
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
function runtimeEnvStatus(env) {
|
|
161
|
+
return Object.fromEntries(Object.entries(SHORTLINKS_RUNTIME_ENV).map(([key, name]) => {
|
|
162
|
+
const activeName = getShortlinksRuntimeEnvName(env, key);
|
|
163
|
+
return [
|
|
164
|
+
key,
|
|
165
|
+
{
|
|
166
|
+
name,
|
|
167
|
+
active_name: activeName,
|
|
168
|
+
configured: Boolean(clean(env[activeName]))
|
|
169
|
+
}
|
|
170
|
+
];
|
|
171
|
+
}));
|
|
172
|
+
}
|
|
173
|
+
function readRuntimeEnv(env, key) {
|
|
174
|
+
const primary = SHORTLINKS_RUNTIME_ENV[key];
|
|
175
|
+
const primaryValue = clean(env[primary]);
|
|
176
|
+
if (primaryValue)
|
|
177
|
+
return { name: primary, value: primaryValue };
|
|
178
|
+
const fallback = SHORTLINKS_RUNTIME_FALLBACK_ENV[key];
|
|
179
|
+
return { name: fallback, value: clean(env[fallback]) };
|
|
180
|
+
}
|
|
181
|
+
function parseBoolean(value, fallback) {
|
|
182
|
+
const normalized = clean(value)?.toLowerCase();
|
|
183
|
+
if (!normalized)
|
|
184
|
+
return fallback;
|
|
185
|
+
if (["1", "true", "yes", "on"].includes(normalized))
|
|
186
|
+
return true;
|
|
187
|
+
if (["0", "false", "no", "off"].includes(normalized))
|
|
188
|
+
return false;
|
|
189
|
+
throw new Error(`${SHORTLINKS_RUNTIME_ENV.databaseSsl} must be true or false`);
|
|
190
|
+
}
|
|
191
|
+
function isSensitiveQueryKey(key) {
|
|
192
|
+
return /(?:^|[_-])(pass(?:word)?|pwd|secret|token|credential|auth|api[_-]?key|access[_-]?key)(?:$|[_-])/i.test(key);
|
|
193
|
+
}
|
|
194
|
+
function clean(value) {
|
|
195
|
+
const trimmed = value?.trim();
|
|
196
|
+
return trimmed ? trimmed : undefined;
|
|
197
|
+
}
|
|
198
|
+
export {
|
|
199
|
+
redactDatabaseUrl,
|
|
200
|
+
parseShortlinksStoreMode,
|
|
201
|
+
loadShortlinksRuntimeConfig,
|
|
202
|
+
getShortlinksStoreMode,
|
|
203
|
+
getShortlinksRuntimeStatus,
|
|
204
|
+
getShortlinksRuntimeEnvName,
|
|
205
|
+
getShortlinksDatabaseUrl,
|
|
206
|
+
getShortlinksDatabaseSsl,
|
|
207
|
+
getCanonicalShortlinksPostgresConfig,
|
|
208
|
+
assertShortlinksPostgresConfig,
|
|
209
|
+
SHORTLINKS_RUNTIME_FALLBACK_ENV,
|
|
210
|
+
SHORTLINKS_RUNTIME_ENV,
|
|
211
|
+
CANONICAL_SHORTLINKS_RUNTIME_SECRET_PATH,
|
|
212
|
+
CANONICAL_SHORTLINKS_POSTGRES_DATABASE,
|
|
213
|
+
CANONICAL_SHORTLINKS_POSTGRES_CLUSTER
|
|
214
|
+
};
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
export interface Link {
|
|
2
|
+
"id": string;
|
|
3
|
+
"domain_id": string;
|
|
4
|
+
"hostname": string;
|
|
5
|
+
"slug": string;
|
|
6
|
+
"destination_url": string;
|
|
7
|
+
"title"?: string | null;
|
|
8
|
+
"active": boolean;
|
|
9
|
+
"expires_at"?: string | null;
|
|
10
|
+
"short_url"?: string;
|
|
11
|
+
"metadata"?: Record<string, unknown>;
|
|
12
|
+
"created_at": string;
|
|
13
|
+
"updated_at"?: string;
|
|
14
|
+
}
|
|
15
|
+
export interface Domain {
|
|
16
|
+
"id": string;
|
|
17
|
+
"hostname": string;
|
|
18
|
+
"provider": string;
|
|
19
|
+
"default_domain": boolean;
|
|
20
|
+
"origin_url"?: string | null;
|
|
21
|
+
"notes"?: string | null;
|
|
22
|
+
"metadata"?: Record<string, unknown>;
|
|
23
|
+
"created_at": string;
|
|
24
|
+
"updated_at"?: string;
|
|
25
|
+
}
|
|
26
|
+
export interface LinkStats {
|
|
27
|
+
"link": Link;
|
|
28
|
+
"clicks": number;
|
|
29
|
+
"last_clicked_at"?: string | null;
|
|
30
|
+
"top_referrers"?: Array<{
|
|
31
|
+
"referer"?: string | null;
|
|
32
|
+
"clicks"?: number;
|
|
33
|
+
}>;
|
|
34
|
+
"top_user_agents"?: Array<{
|
|
35
|
+
"user_agent"?: string | null;
|
|
36
|
+
"clicks"?: number;
|
|
37
|
+
}>;
|
|
38
|
+
}
|
|
39
|
+
export type LinkList = Array<{
|
|
40
|
+
"id": string;
|
|
41
|
+
"domain_id": string;
|
|
42
|
+
"hostname": string;
|
|
43
|
+
"slug": string;
|
|
44
|
+
"destination_url": string;
|
|
45
|
+
"title"?: string | null;
|
|
46
|
+
"active": boolean;
|
|
47
|
+
"expires_at"?: string | null;
|
|
48
|
+
"short_url"?: string;
|
|
49
|
+
"metadata"?: Record<string, unknown>;
|
|
50
|
+
"created_at": string;
|
|
51
|
+
"updated_at"?: string;
|
|
52
|
+
}>;
|
|
53
|
+
export type DomainList = Array<{
|
|
54
|
+
"id": string;
|
|
55
|
+
"hostname": string;
|
|
56
|
+
"provider": string;
|
|
57
|
+
"default_domain": boolean;
|
|
58
|
+
"origin_url"?: string | null;
|
|
59
|
+
"notes"?: string | null;
|
|
60
|
+
"metadata"?: Record<string, unknown>;
|
|
61
|
+
"created_at": string;
|
|
62
|
+
"updated_at"?: string;
|
|
63
|
+
}>;
|
|
64
|
+
export interface TotalStats {
|
|
65
|
+
"domains": number;
|
|
66
|
+
"links": number;
|
|
67
|
+
"clicks": number;
|
|
68
|
+
}
|
|
69
|
+
export interface CreateLinkRequest {
|
|
70
|
+
"url": string;
|
|
71
|
+
"domain"?: string;
|
|
72
|
+
"slug"?: string;
|
|
73
|
+
"title"?: string;
|
|
74
|
+
"expires_at"?: string;
|
|
75
|
+
"length"?: number;
|
|
76
|
+
"metadata"?: Record<string, unknown>;
|
|
77
|
+
}
|
|
78
|
+
export interface AddDomainRequest {
|
|
79
|
+
"hostname": string;
|
|
80
|
+
"provider"?: string;
|
|
81
|
+
"default"?: boolean;
|
|
82
|
+
"origin_url"?: string;
|
|
83
|
+
"notes"?: string;
|
|
84
|
+
"metadata"?: Record<string, unknown>;
|
|
85
|
+
}
|
|
86
|
+
export interface DeleteResponse {
|
|
87
|
+
"deleted": boolean;
|
|
88
|
+
"slug"?: string;
|
|
89
|
+
}
|
|
90
|
+
export interface HealthStatus {
|
|
91
|
+
"status": string;
|
|
92
|
+
"version": string;
|
|
93
|
+
"mode": string;
|
|
94
|
+
"db_latency_ms"?: number;
|
|
95
|
+
}
|
|
96
|
+
export interface ReadyStatus {
|
|
97
|
+
"status": string;
|
|
98
|
+
"version": string;
|
|
99
|
+
"mode": string;
|
|
100
|
+
"pending_migrations"?: Array<string>;
|
|
101
|
+
}
|
|
102
|
+
export interface VersionInfo {
|
|
103
|
+
"status": string;
|
|
104
|
+
"version": string;
|
|
105
|
+
"mode": string;
|
|
106
|
+
"name"?: string;
|
|
107
|
+
}
|
|
108
|
+
export interface ErrorResponse {
|
|
109
|
+
"error": string;
|
|
110
|
+
"reason"?: string;
|
|
111
|
+
}
|
|
112
|
+
export interface ShortlinksApiClientOptions {
|
|
113
|
+
/** Base URL, e.g. process.env.APP_API_URL. */
|
|
114
|
+
baseUrl: string;
|
|
115
|
+
/** API key, e.g. process.env.APP_API_KEY. Sent as the 'x-api-key' header. */
|
|
116
|
+
apiKey?: string;
|
|
117
|
+
/** Custom fetch (defaults to global fetch). */
|
|
118
|
+
fetch?: typeof fetch;
|
|
119
|
+
/** Extra headers merged into every request. */
|
|
120
|
+
headers?: Record<string, string>;
|
|
121
|
+
}
|
|
122
|
+
export declare class ApiError extends Error {
|
|
123
|
+
readonly status: number;
|
|
124
|
+
readonly body: unknown;
|
|
125
|
+
constructor(status: number, message: string, body: unknown);
|
|
126
|
+
}
|
|
127
|
+
export declare class ShortlinksApiClient {
|
|
128
|
+
private readonly baseUrl;
|
|
129
|
+
private readonly apiKey;
|
|
130
|
+
private readonly fetchImpl;
|
|
131
|
+
private readonly baseHeaders;
|
|
132
|
+
constructor(options: ShortlinksApiClientOptions);
|
|
133
|
+
private request;
|
|
134
|
+
/** Liveness probe. */
|
|
135
|
+
getHealth(init?: RequestInit): Promise<HealthStatus>;
|
|
136
|
+
/** Readiness probe (DB reachable and schema migrated). */
|
|
137
|
+
getReady(init?: RequestInit): Promise<ReadyStatus>;
|
|
138
|
+
/** List configured domains. */
|
|
139
|
+
listDomains(init?: RequestInit): Promise<DomainList>;
|
|
140
|
+
/** Add or update a domain. */
|
|
141
|
+
addDomain(body: AddDomainRequest, init?: RequestInit): Promise<Domain>;
|
|
142
|
+
/** List shortlinks. */
|
|
143
|
+
listLinks(query?: {
|
|
144
|
+
"domain"?: string;
|
|
145
|
+
"active"?: boolean;
|
|
146
|
+
"limit"?: number;
|
|
147
|
+
}, init?: RequestInit): Promise<LinkList>;
|
|
148
|
+
/** Create a shortlink. */
|
|
149
|
+
createLink(body: CreateLinkRequest, init?: RequestInit): Promise<Link>;
|
|
150
|
+
/** Get a shortlink by slug. */
|
|
151
|
+
getLink(slug: string, query?: {
|
|
152
|
+
"domain"?: string;
|
|
153
|
+
}, init?: RequestInit): Promise<Link>;
|
|
154
|
+
/** Delete a shortlink. */
|
|
155
|
+
deleteLink(slug: string, query?: {
|
|
156
|
+
"domain"?: string;
|
|
157
|
+
}, init?: RequestInit): Promise<DeleteResponse>;
|
|
158
|
+
/** Disable a shortlink. */
|
|
159
|
+
disableLink(slug: string, query?: {
|
|
160
|
+
"domain"?: string;
|
|
161
|
+
}, init?: RequestInit): Promise<Link>;
|
|
162
|
+
/** Enable a shortlink. */
|
|
163
|
+
enableLink(slug: string, query?: {
|
|
164
|
+
"domain"?: string;
|
|
165
|
+
}, init?: RequestInit): Promise<Link>;
|
|
166
|
+
/** Click stats for a shortlink. */
|
|
167
|
+
getLinkStats(slug: string, query?: {
|
|
168
|
+
"domain"?: string;
|
|
169
|
+
}, init?: RequestInit): Promise<LinkStats>;
|
|
170
|
+
/** Resolve a slug to its destination without recording a click. */
|
|
171
|
+
resolveLink(slug: string, query?: {
|
|
172
|
+
"domain"?: string;
|
|
173
|
+
}, init?: RequestInit): Promise<Link>;
|
|
174
|
+
/** Total domains/links/clicks counts. */
|
|
175
|
+
getStats(init?: RequestInit): Promise<TotalStats>;
|
|
176
|
+
/** Service version and mode. */
|
|
177
|
+
getVersion(init?: RequestInit): Promise<VersionInfo>;
|
|
178
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @hasna/shortlinks/sdk — typed client for the shortlinks REST API.
|
|
3
|
+
*
|
|
4
|
+
* The generated client (`ShortlinksApiClient`) is produced from the serve
|
|
5
|
+
* OpenAPI document (src/serve/openapi.ts) by `bun run sdk:generate`. It is the
|
|
6
|
+
* canonical client for the versioned `/v1` API with API-key auth.
|
|
7
|
+
*
|
|
8
|
+
* Client self_hosted mode reads `SHORTLINKS_API_URL` + `SHORTLINKS_API_KEY`
|
|
9
|
+
* (never a DSN).
|
|
10
|
+
*/
|
|
11
|
+
export * from "./generated.js";
|
|
12
|
+
export { buildOpenApiDocument } from "../serve/openapi.js";
|