@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.
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Capability-bearing URL projection.
3
+ *
4
+ * Incident 716957 (todos b03cc058): a stored destination that is itself a
5
+ * signed capability URL (an S3 presigned read URL, GCS, or CloudFront signed
6
+ * URL) was emitted verbatim by the CLI into a probe file and reproduced in a
7
+ * session transcript, granting bearer read access until expiry. `secrets scan`
8
+ * does not cover this class, so consumer-side containment is the interim
9
+ * behaviour required by the capability-bearing-output doctrine.
10
+ *
11
+ * Output therefore projects such a URL to its plain unsigned reference — the
12
+ * scheme/host/path with every capability query parameter stripped. A consumer
13
+ * resolving the projected reference goes through the normal unsigned path and
14
+ * never receives a bearer credential from a transcript.
15
+ */
16
+ import type { Link } from "../types.js";
17
+ /** True when `url` is an http(s) URL whose query carries a signed-capability parameter. */
18
+ export declare function hasCapabilityQuery(url: string): boolean;
19
+ /**
20
+ * Project `url` to its plain unsigned reference: the same scheme/host/path
21
+ * with every capability query parameter stripped and non-capability parameters
22
+ * preserved. Non-capability or malformed values are returned unchanged.
23
+ */
24
+ export declare function projectDestinationUrl(url: string): string;
25
+ /** Project a Link record's destination_url (identity when already plain). */
26
+ export declare function projectLink(link: Link): Link;
27
+ /**
28
+ * Project a CLI payload for output: a Link, an array of Links, or a LinkStats
29
+ * record get their destination_url projected; every other payload passes
30
+ * through untouched (same object reference).
31
+ */
32
+ export declare function projectForOutput(data: unknown): unknown;
@@ -1,8 +1,7 @@
1
1
  import { CloudShortlinksStore } from "./cloud-store.js";
2
- import type { Env } from "@hasna/contracts/mode";
3
- import type { ListLinksOptions, Store, TotalStats } from "./store-interface.js";
2
+ import type { Env, ListLinksOptions, Store, TotalStats } from "./store-interface.js";
4
3
  import type { AddDomainInput, Click, ClickInput, CreateLinkInput, Domain, Link, LinkStats } from "./types.js";
5
- /** The self_hosted/cloud HTTP transport. Same client code for both tiers. */
4
+ /** The hosted-API HTTP transport. */
6
5
  export { CloudShortlinksStore as ApiStore } from "./cloud-store.js";
7
6
  export type { Store } from "./store-interface.js";
8
7
  /**
@@ -30,15 +29,16 @@ export declare class LocalStore implements Store {
30
29
  close(): Promise<void>;
31
30
  }
32
31
  export interface ResolveStoreOptions {
33
- /** Explicit local SQLite path (CLI `--db`); ignored in cloud mode. */
32
+ /** Explicit local SQLite path (CLI `--db`); ignored when the hosted API is selected. */
34
33
  dbPath?: string;
35
- /** Transport overrides for the cloud client (test injection: fetchImpl, ...). */
34
+ /** Transport overrides for the hosted-API client (test injection: fetchImpl, ...). */
36
35
  cloudOverrides?: Parameters<typeof CloudShortlinksStore.fromEnv>[1];
37
36
  }
38
37
  /**
39
38
  * Resolve the active {@link Store} for the current environment. Returns the
40
- * cloud {@link ApiStore} when the client flip is on, otherwise a
41
- * {@link LocalStore}. Throws when cloud was requested but is misconfigured.
39
+ * hosted-API {@link ApiStore} when the client env is fully configured,
40
+ * otherwise a {@link LocalStore}. Throws when the hosted client is partially
41
+ * configured.
42
42
  */
43
43
  export declare function resolveStore(env?: Env, options?: ResolveStoreOptions): Store;
44
44
  /**
@@ -1,6 +1,5 @@
1
1
  import { resolveStorageClient, type HasnaStorageClient } from "@hasna/contracts/client/storage";
2
- import type { Env } from "@hasna/contracts/mode";
3
- import type { Store } from "./store-interface.js";
2
+ import type { Env, Store } from "./store-interface.js";
4
3
  import type { AddDomainInput, Click, ClickInput, CreateLinkInput, Domain, Link, LinkStats } from "./types.js";
5
4
  /**
6
5
  * Cloud-backed shortlinks store. All methods hit `/v1` over HTTPS with the
@@ -9,16 +8,19 @@ import type { AddDomainInput, Click, ClickInput, CreateLinkInput, Domain, Link,
9
8
  */
10
9
  export declare class CloudShortlinksStore implements Store {
11
10
  private readonly client;
12
- readonly kind: "cloud-http";
11
+ readonly kind: "http";
13
12
  readonly transport: HasnaStorageClient["transport"];
14
13
  private constructor();
15
14
  /** Base `<origin>/v1` URL this store targets (for status/diagnostics). */
16
15
  get baseUrl(): string;
17
16
  /**
18
- * Resolve a cloud store from the environment. Returns the store when the
19
- * client-flip resolves to `cloud-http` (self_hosted + API_URL + API_KEY), else
20
- * null so the caller falls back to the local store. Throws only when cloud was
21
- * explicitly requested but is misconfigured (never silent local drift).
17
+ * Resolve a hosted-API store from the environment. The contracts client
18
+ * seam (`resolveStorageClient`) decides: an explicit API URL + API key in
19
+ * the environment selects the hosted client, and the fleet app-config on
20
+ * disk is the fallback tier; otherwise the caller uses its local store.
21
+ * Throws when only one of URL/key is set in the environment tier — a
22
+ * partially configured hosted client must fail loudly, never silently
23
+ * drift to the local dataset.
22
24
  */
23
25
  static fromEnv(env?: Env, overrides?: Parameters<typeof resolveStorageClient>[2]): CloudShortlinksStore | null;
24
26
  close(): Promise<void>;
@@ -0,0 +1,19 @@
1
+ export declare const SERVER_DATA_BACKENDS: readonly ["sqlite", "postgresql"];
2
+ export type ServerDataBackend = (typeof SERVER_DATA_BACKENDS)[number];
3
+ export type Env = Record<string, string | undefined>;
4
+ /** Upper-snake env token for an app name, e.g. `todos` -> `TODOS`. */
5
+ export declare function envToken(name: string): string;
6
+ export interface ServerDataBackendEnvKeys {
7
+ databaseUrlKeys: string[];
8
+ }
9
+ export declare function serverDataBackendEnvKeys(name: string): ServerDataBackendEnvKeys;
10
+ export declare function assertNoLegacyStorageMode(name: string, env?: Env): void;
11
+ export interface ServerDataBackendResolution {
12
+ backend: ServerDataBackend;
13
+ source: string;
14
+ databaseUrlPresent: boolean;
15
+ databaseUrlSource: string | null;
16
+ }
17
+ export declare function resolveServerDataBackend(name: string, env?: Env): ServerDataBackendResolution;
18
+ /** Resolve the database URL without logging it. Returns `null` when unset. */
19
+ export declare function resolveDatabaseUrl(name: string, env?: Env): string | null;
@@ -1,5 +1,5 @@
1
- export declare const KIT_VERSION = "0.4.2";
2
- export * from "./mode.js";
1
+ export declare const KIT_VERSION = "0.11.1";
2
+ export * from "./backend.js";
3
3
  export * from "./tls.js";
4
4
  export * from "./query.js";
5
5
  export * from "./pool.js";
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Read `key` from `source` only when `source` OWNS it.
3
+ *
4
+ * Returns `undefined` for an inherited property and for a null/undefined or
5
+ * non-object source, so a guarded read is a drop-in for `source?.[key]` that
6
+ * cannot be answered by the prototype chain.
7
+ */
8
+ export declare function ownProp<T>(source: unknown, key: string): T | undefined;
9
+ /** `ownProp` narrowed to a string, so a polluted non-string cannot slip through. */
10
+ export declare function ownString(source: unknown, key: string): string | undefined;
@@ -14,20 +14,21 @@ export interface CreatePgPoolOptions extends TlsResolveOptions {
14
14
  }
15
15
  /** Build a `pg.Pool` with fleet-standard TLS handling. */
16
16
  export declare function createPgPool(options: CreatePgPoolOptions): Pool;
17
- export interface CreateCloudPoolFromEnvOptions extends TlsResolveOptions {
17
+ export interface CreateServerPoolFromEnvOptions extends TlsResolveOptions {
18
18
  max?: number;
19
19
  idleTimeoutMillis?: number;
20
20
  connectionTimeoutMillis?: number;
21
21
  applicationName?: string;
22
22
  }
23
- export interface CloudPoolFromEnv {
23
+ export interface ServerPoolFromEnv {
24
24
  client: PoolQueryClient;
25
25
  connectionSource: string;
26
26
  }
27
27
  /**
28
- * Resolve mode + database URL from the environment and build a cloud pool.
28
+ * Resolve backend + database URL from the environment and build the server's
29
+ * PostgreSQL pool.
29
30
  *
30
- * Throws when the resolved mode is not `cloud` (PURE REMOTE has no Postgres in
31
- * `local` mode) or when the database URL is missing. Never logs the URL.
31
+ * Throws when no database URL selects the `postgresql` backend. Never logs the
32
+ * URL.
32
33
  */
33
- export declare function createCloudPoolFromEnv(appName: string, options?: CreateCloudPoolFromEnvOptions): CloudPoolFromEnv;
34
+ export declare function createServerPoolFromEnv(appName: string, options?: CreateServerPoolFromEnvOptions): ServerPoolFromEnv;
@@ -2,6 +2,9 @@
2
2
  export type PgSslConfig = boolean | {
3
3
  rejectUnauthorized: boolean;
4
4
  ca?: string;
5
+ cert?: string;
6
+ key?: string;
7
+ passphrase?: string;
5
8
  };
6
9
  export interface TlsResolveOptions {
7
10
  /** Inline CA bundle (PEM). Wins over every other CA source. */
@@ -12,14 +15,38 @@ export interface TlsResolveOptions {
12
15
  env?: Record<string, string | undefined>;
13
16
  }
14
17
  export type SslMode = "disable" | "prefer" | "require" | "verify-ca" | "verify-full";
18
+ /**
19
+ * Remove the TLS query parameters once this module has resolved them into an
20
+ * explicit `ssl` option. pg re-parses `connectionString` AFTER merging pool
21
+ * options and lets the parse win, so leaving `sslmode` (or `ssl`, `sslcert`,
22
+ * `sslkey`, `sslrootcert`, `sslnegotiation`) in the URL replaces the resolved
23
+ * SSL object with pg's own — discarding the CA bundle with it.
24
+ *
25
+ * Non-TLS parameters and any fragment are preserved exactly.
26
+ */
27
+ export declare function connectionStringWithoutTlsParameters(connectionString: string): string;
28
+ /**
29
+ * Preserve pg's transport negotiation choice outside the stripped URL, so
30
+ * `sslnegotiation=direct` survives as an explicit pool option instead of being
31
+ * silently dropped.
32
+ */
33
+ export declare function sslNegotiationFromConnectionString(connectionString: string): "postgres" | "direct" | undefined;
15
34
  /**
16
35
  * Extract the effective `sslmode` from a Postgres connection string. Honors the
17
- * `sslmode` query param and the legacy `ssl=true` boolean. Returns `disable`
18
- * when TLS is not requested.
36
+ * `sslmode` query param, the legacy `ssl=true` boolean, and pg's rule that
37
+ * `sslnegotiation=direct` implies TLS when no explicit SSL setting is present.
38
+ * Returns `disable` when TLS is not requested.
19
39
  */
20
40
  export declare function sslModeFromConnectionString(connectionString: string): SslMode;
21
41
  /**
22
42
  * Resolve the `pg` ssl config for a connection string. See the module header
23
- * for the full mode table. Returns `undefined` when TLS should be off.
43
+ * for the full mode table.
44
+ *
45
+ * Returns `false` when TLS was explicitly switched off, and `undefined` when the
46
+ * DSN expressed no TLS policy at all — those are different answers, and pg
47
+ * treats them differently: only `undefined` lets `PGSSLMODE` decide.
48
+ *
49
+ * The caller MUST hand pg `connectionStringWithoutTlsParameters(connectionString)`
50
+ * rather than the original DSN, or pg discards everything resolved here.
24
51
  */
25
52
  export declare function resolveTlsConfig(connectionString: string, options?: TlsResolveOptions): PgSslConfig | undefined;