@hasna/recordings 0.1.35 → 0.1.37

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
@@ -42,6 +42,49 @@ MCP_HTTP=1 MCP_HTTP_PORT=8829 recordings-mcp
42
42
 
43
43
  Endpoints: `GET /health` → `{"status":"ok","name":"recordings"}`, MCP at `/mcp`.
44
44
 
45
+ ## HTTP API (`recordings-serve`)
46
+
47
+ `recordings-serve` is the self-hosted HTTP API. In cloud mode it is PURE REMOTE
48
+ (Amendment A1): the process reads/writes the shared cloud Postgres directly with
49
+ API-key auth via [`@hasna/contracts`](https://www.npmjs.com/package/@hasna/contracts).
50
+
51
+ ```bash
52
+ recordings-serve --port 8874 # start the API
53
+ recordings-serve migrate # apply the cloud schema, then exit
54
+ ```
55
+
56
+ Service surface (unauthenticated): `GET /health`, `GET /ready`, `GET /version`
57
+ (each returns `{status, version, mode}`), and `GET /openapi.json` (the OpenAPI
58
+ 3.1 document the SDK is generated from).
59
+
60
+ Versioned API (`/v1/*`, API-key auth via `x-api-key` or `Authorization: Bearer`):
61
+
62
+ | Method | Path | Scope |
63
+ | ------ | ---- | ----- |
64
+ | GET/POST | `/v1/recordings` | `recordings:read` / `recordings:write` |
65
+ | GET/DELETE | `/v1/recordings/:id` | `recordings:read` / `recordings:write` |
66
+ | GET | `/v1/stats` | `recordings:read` |
67
+ | GET/POST | `/v1/agents` · GET `/v1/agents/:id` | `recordings:read` / `recordings:write` |
68
+ | GET/POST | `/v1/projects` · GET `/v1/projects/:id` | `recordings:read` / `recordings:write` |
69
+
70
+ Env: `HASNA_RECORDINGS_DATABASE_URL` (remote Postgres DSN — enables cloud `/v1`)
71
+ and `HASNA_RECORDINGS_API_SIGNING_KEY` (HMAC signing secret for API-key auth).
72
+
73
+ ## SDK
74
+
75
+ The typed `/v1` client is generated from the serve OpenAPI document
76
+ (`bun run generate:sdk`):
77
+
78
+ ```ts
79
+ import { RecordingsV1Client } from "@hasna/recordings/sdk";
80
+
81
+ const client = new RecordingsV1Client({
82
+ baseUrl: process.env.RECORDINGS_API_URL!,
83
+ apiKey: process.env.RECORDINGS_API_KEY!,
84
+ });
85
+ const { recordings } = await client.listRecordings({ limit: 20 });
86
+ ```
87
+
45
88
  ## Storage Sync
46
89
 
47
90
  This package has native local/remote sync. Local data stays in SQLite under
@@ -49,6 +92,21 @@ This package has native local/remote sync. Local data stays in SQLite under
49
92
  `HASNA_RECORDINGS_DATABASE_URL` is set or `~/.hasna/recordings/storage/config.json` is
50
93
  configured.
51
94
 
95
+ The optional config file uses a `postgres` object:
96
+
97
+ ```json
98
+ {
99
+ "mode": "remote",
100
+ "postgres": {
101
+ "host": "db.example",
102
+ "port": 5432,
103
+ "username": "recordings",
104
+ "password_env": "RECORDINGS_DATABASE_PASSWORD",
105
+ "ssl": true
106
+ }
107
+ }
108
+ ```
109
+
52
110
  ```bash
53
111
  recordings storage status
54
112
  recordings storage migrate
@@ -57,6 +115,8 @@ recordings storage pull
57
115
  ```
58
116
 
59
117
  `RECORDINGS_DATABASE_URL` is accepted as the non-Hasna fallback database URL.
118
+ `HASNA_RECORDINGS_STORAGE_CONFIG` can point automation at a non-default storage
119
+ config file.
60
120
 
61
121
  ## Data Directory
62
122
 
package/dist/cli/index.js CHANGED
@@ -5098,7 +5098,7 @@ var init_pg_migrate = __esm(() => {
5098
5098
  var require_package = __commonJS((exports, module) => {
5099
5099
  module.exports = {
5100
5100
  name: "@hasna/recordings",
5101
- version: "0.1.35",
5101
+ version: "0.1.37",
5102
5102
  type: "module",
5103
5103
  description: "Speech-to-text recording tool with MCP and CLI \u2014 records, transcribes, and optionally enhances text using AI",
5104
5104
  repository: {
@@ -5109,7 +5109,8 @@ var require_package = __commonJS((exports, module) => {
5109
5109
  types: "dist/index.d.ts",
5110
5110
  bin: {
5111
5111
  recordings: "dist/cli/index.js",
5112
- "recordings-mcp": "dist/mcp/index.js"
5112
+ "recordings-mcp": "dist/mcp/index.js",
5113
+ "recordings-serve": "dist/server/index.js"
5113
5114
  },
5114
5115
  exports: {
5115
5116
  ".": {
@@ -5119,20 +5120,29 @@ var require_package = __commonJS((exports, module) => {
5119
5120
  "./storage": {
5120
5121
  import: "./dist/storage.js",
5121
5122
  types: "./dist/storage.d.ts"
5123
+ },
5124
+ "./sdk": {
5125
+ import: "./dist/sdk/index.js",
5126
+ types: "./dist/sdk/index.d.ts"
5122
5127
  }
5123
5128
  },
5124
5129
  scripts: {
5125
5130
  clean: "rm -rf dist",
5126
- build: "bun run clean && bun run build:cli && bun run build:mcp && bun run build:lib && tsc --emitDeclarationOnly --outDir dist",
5131
+ build: "bun run clean && bun run build:cli && bun run build:mcp && bun run build:serve && bun run build:lib && tsc --emitDeclarationOnly --outDir dist",
5127
5132
  "build:cli": "bun build src/cli/index.ts --target=bun --outfile=dist/cli/index.js --external=commander --external=chalk --external=openai",
5128
5133
  "build:mcp": "bun build src/mcp/index.ts --target=bun --outfile=dist/mcp/index.js --external=@modelcontextprotocol/sdk --external=openai",
5129
- "build:lib": "bun build src/index.ts src/storage.ts --target=bun --outdir=dist --external=openai",
5134
+ "build:serve": "bun build src/server/index.ts --target=bun --outfile=dist/server/index.js --external=@modelcontextprotocol/sdk --external=@hasna/contracts --external=openai --external=pg",
5135
+ "build:lib": "bun build src/index.ts src/storage.ts src/sdk/index.ts --target=bun --outdir=dist --external=openai",
5136
+ "generate:sdk": "bun run scripts/generate-sdk.ts",
5137
+ migrate: "bun run scripts/migrate.ts",
5130
5138
  typecheck: "tsc --noEmit",
5131
5139
  test: "bun test",
5132
5140
  "test:coverage": "bun test --coverage",
5133
5141
  "dev:cli": "bun run src/cli/index.ts",
5134
5142
  "dev:mcp": "bun run src/mcp/index.ts",
5135
- prepack: "bun run build",
5143
+ "verify:release": "bun run scripts/release-guard.ts",
5144
+ prepack: "bun run build && bun run verify:release",
5145
+ prepublishOnly: "bun run typecheck && bun run test",
5136
5146
  postinstall: "bash scripts/install_macos_app.sh --postinstall"
5137
5147
  },
5138
5148
  files: [
@@ -5148,6 +5158,7 @@ var require_package = __commonJS((exports, module) => {
5148
5158
  "LICENSE"
5149
5159
  ],
5150
5160
  dependencies: {
5161
+ "@hasna/contracts": "0.4.1",
5151
5162
  "@hasna/events": "^0.1.11",
5152
5163
  "@modelcontextprotocol/sdk": "^1.12.1",
5153
5164
  chalk: "^5.4.1",
@@ -6989,7 +7000,7 @@ async function processText(rawText, config, systemPrompt) {
6989
7000
  }
6990
7001
 
6991
7002
  // src/version.ts
6992
- var VERSION = "0.1.35";
7003
+ var VERSION = "0.1.37";
6993
7004
 
6994
7005
  // src/cli/storage.ts
6995
7006
  import chalk from "chalk";
@@ -6998,11 +7009,12 @@ import chalk from "chalk";
6998
7009
  import { existsSync as existsSync4, readFileSync as readFileSync2 } from "fs";
6999
7010
  import { homedir as homedir3 } from "os";
7000
7011
  import { join as join4 } from "path";
7001
- var STORAGE_CONFIG_PATH = join4(homedir3(), ".hasna", "recordings", "storage", "config.json");
7012
+ var LEGACY_DATABASE_CONFIG_KEY = ["r", "d", "s"].join("");
7002
7013
  var RECORDINGS_STORAGE_ENV = "HASNA_RECORDINGS_DATABASE_URL";
7003
7014
  var RECORDINGS_STORAGE_FALLBACK_ENV = "RECORDINGS_DATABASE_URL";
7004
7015
  var RECORDINGS_STORAGE_MODE_ENV = "HASNA_RECORDINGS_STORAGE_MODE";
7005
7016
  var RECORDINGS_STORAGE_MODE_FALLBACK_ENV = "RECORDINGS_STORAGE_MODE";
7017
+ var RECORDINGS_STORAGE_CONFIG_ENV = "HASNA_RECORDINGS_STORAGE_CONFIG";
7006
7018
  var STORAGE_DATABASE_ENV = [RECORDINGS_STORAGE_ENV, RECORDINGS_STORAGE_FALLBACK_ENV];
7007
7019
  function readEnv(name) {
7008
7020
  const value = process.env[name]?.trim();
@@ -7029,10 +7041,16 @@ function getStorageDatabaseUrl() {
7029
7041
  const env = getStorageDatabaseEnv();
7030
7042
  return env ? readEnv(env.name) : undefined;
7031
7043
  }
7044
+ function getStorageConfigPath() {
7045
+ const override = readEnv(RECORDINGS_STORAGE_CONFIG_ENV);
7046
+ if (override)
7047
+ return override;
7048
+ return join4(homedir3(), ".hasna", "recordings", "storage", "config.json");
7049
+ }
7032
7050
  function getStorageConfig() {
7033
7051
  const config = {
7034
7052
  mode: "local",
7035
- rds: {
7053
+ postgres: {
7036
7054
  host: "",
7037
7055
  port: 5432,
7038
7056
  username: "",
@@ -7040,11 +7058,13 @@ function getStorageConfig() {
7040
7058
  ssl: true
7041
7059
  }
7042
7060
  };
7043
- if (existsSync4(STORAGE_CONFIG_PATH)) {
7061
+ const storageConfigPath = getStorageConfigPath();
7062
+ if (existsSync4(storageConfigPath)) {
7044
7063
  try {
7045
- const raw = JSON.parse(readFileSync2(STORAGE_CONFIG_PATH, "utf-8"));
7064
+ const raw = JSON.parse(readFileSync2(storageConfigPath, "utf-8"));
7065
+ const legacyDatabaseConfig = typeof raw[LEGACY_DATABASE_CONFIG_KEY] === "object" && raw[LEGACY_DATABASE_CONFIG_KEY] !== null ? raw[LEGACY_DATABASE_CONFIG_KEY] : {};
7046
7066
  config.mode = normalizeMode(raw.mode) ?? config.mode;
7047
- config.rds = { ...config.rds, ...raw.rds ?? {} };
7067
+ config.postgres = { ...config.postgres, ...legacyDatabaseConfig, ...raw.postgres ?? {} };
7048
7068
  } catch {}
7049
7069
  }
7050
7070
  const modeOverride = readEnv(RECORDINGS_STORAGE_MODE_ENV) ?? readEnv(RECORDINGS_STORAGE_MODE_FALLBACK_ENV);
@@ -7061,7 +7081,7 @@ function getStorageConnectionString(dbName = "recordings") {
7061
7081
  if (direct)
7062
7082
  return direct;
7063
7083
  const config = getStorageConfig();
7064
- const { host, port, username, password_env, ssl } = config.rds;
7084
+ const { host, port, username, password_env, ssl } = config.postgres;
7065
7085
  if (!host || !username) {
7066
7086
  throw new Error("Storage database is not configured. Set HASNA_RECORDINGS_DATABASE_URL or configure ~/.hasna/recordings/storage/config.json.");
7067
7087
  }
@@ -7146,8 +7166,9 @@ async function runStorageMigrations(remote) {
7146
7166
  function getStorageStatus(db = getDatabase()) {
7147
7167
  const config = getStorageConfig();
7148
7168
  const activeEnv = getStorageDatabaseEnv();
7169
+ const hasConfiguredPostgres = Boolean(config.postgres.host && config.postgres.username);
7149
7170
  return {
7150
- configured: Boolean(activeEnv),
7171
+ configured: Boolean(activeEnv) || hasConfiguredPostgres,
7151
7172
  mode: config.mode,
7152
7173
  enabled: config.mode === "hybrid" || config.mode === "remote",
7153
7174
  env: STORAGE_DATABASE_ENV,
@@ -1,7 +1,7 @@
1
1
  export type StorageMode = "local" | "hybrid" | "remote";
2
2
  export interface StorageConfig {
3
3
  mode: StorageMode;
4
- rds: {
4
+ postgres: {
5
5
  host: string;
6
6
  port: number;
7
7
  username: string;
@@ -16,6 +16,7 @@ export declare const RECORDINGS_STORAGE_ENV = "HASNA_RECORDINGS_DATABASE_URL";
16
16
  export declare const RECORDINGS_STORAGE_FALLBACK_ENV = "RECORDINGS_DATABASE_URL";
17
17
  export declare const RECORDINGS_STORAGE_MODE_ENV = "HASNA_RECORDINGS_STORAGE_MODE";
18
18
  export declare const RECORDINGS_STORAGE_MODE_FALLBACK_ENV = "RECORDINGS_STORAGE_MODE";
19
+ export declare const RECORDINGS_STORAGE_CONFIG_ENV = "HASNA_RECORDINGS_STORAGE_CONFIG";
19
20
  export declare const STORAGE_DATABASE_ENV: readonly ["HASNA_RECORDINGS_DATABASE_URL", "RECORDINGS_DATABASE_URL"];
20
21
  export declare const STORAGE_MODE_ENV: readonly ["HASNA_RECORDINGS_STORAGE_MODE", "RECORDINGS_STORAGE_MODE"];
21
22
  export declare function getStorageDatabaseEnvName(): (typeof STORAGE_DATABASE_ENV)[number] | null;
@@ -1 +1 @@
1
- {"version":3,"file":"storage-config.d.ts","sourceRoot":"","sources":["../../src/db/storage-config.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,WAAW,GAAG,OAAO,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAExD,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,WAAW,CAAC;IAClB,GAAG,EAAE;QACH,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,MAAM,CAAC;QACb,QAAQ,EAAE,MAAM,CAAC;QACjB,YAAY,EAAE,MAAM,CAAC;QACrB,GAAG,EAAE,OAAO,CAAC;KACd,CAAC;CACH;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;CACd;AAGD,eAAO,MAAM,sBAAsB,kCAAkC,CAAC;AACtE,eAAO,MAAM,+BAA+B,4BAA4B,CAAC;AACzE,eAAO,MAAM,2BAA2B,kCAAkC,CAAC;AAC3E,eAAO,MAAM,oCAAoC,4BAA4B,CAAC;AAC9E,eAAO,MAAM,oBAAoB,uEAAqE,CAAC;AACvG,eAAO,MAAM,gBAAgB,uEAA+E,CAAC;AAa7G,wBAAgB,yBAAyB,IAAI,CAAC,OAAO,oBAAoB,CAAC,CAAC,MAAM,CAAC,GAAG,IAAI,CAKxF;AAED,wBAAgB,qBAAqB,IAAI,UAAU,GAAG,IAAI,CAGzD;AAED,wBAAgB,qBAAqB,IAAI,MAAM,GAAG,SAAS,CAG1D;AAED,wBAAgB,gBAAgB,IAAI,aAAa,CA+BhD;AAED,wBAAgB,0BAA0B,CAAC,MAAM,SAAe,GAAG,MAAM,CAiBxE;AAED,eAAO,MAAM,mBAAmB,mCAA6B,CAAC"}
1
+ {"version":3,"file":"storage-config.d.ts","sourceRoot":"","sources":["../../src/db/storage-config.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,WAAW,GAAG,OAAO,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAExD,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,WAAW,CAAC;IAClB,QAAQ,EAAE;QACR,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,MAAM,CAAC;QACb,QAAQ,EAAE,MAAM,CAAC;QACjB,YAAY,EAAE,MAAM,CAAC;QACrB,GAAG,EAAE,OAAO,CAAC;KACd,CAAC;CACH;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;CACd;AAGD,eAAO,MAAM,sBAAsB,kCAAkC,CAAC;AACtE,eAAO,MAAM,+BAA+B,4BAA4B,CAAC;AACzE,eAAO,MAAM,2BAA2B,kCAAkC,CAAC;AAC3E,eAAO,MAAM,oCAAoC,4BAA4B,CAAC;AAC9E,eAAO,MAAM,6BAA6B,oCAAoC,CAAC;AAC/E,eAAO,MAAM,oBAAoB,uEAAqE,CAAC;AACvG,eAAO,MAAM,gBAAgB,uEAA+E,CAAC;AAa7G,wBAAgB,yBAAyB,IAAI,CAAC,OAAO,oBAAoB,CAAC,CAAC,MAAM,CAAC,GAAG,IAAI,CAKxF;AAED,wBAAgB,qBAAqB,IAAI,UAAU,GAAG,IAAI,CAGzD;AAED,wBAAgB,qBAAqB,IAAI,MAAM,GAAG,SAAS,CAG1D;AAQD,wBAAgB,gBAAgB,IAAI,aAAa,CAoChD;AAED,wBAAgB,0BAA0B,CAAC,MAAM,SAAe,GAAG,MAAM,CAiBxE;AAED,eAAO,MAAM,mBAAmB,mCAA6B,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"storage-sync.d.ts","sourceRoot":"","sources":["../../src/db/storage-sync.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE3C,OAAO,EACL,oBAAoB,EAIpB,KAAK,WAAW,EACjB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAKrD,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,GAAG,MAAM,CAAC;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED,MAAM,WAAW,aAAa;IAC5B,UAAU,EAAE,OAAO,CAAC;IACpB,IAAI,EAAE,WAAW,CAAC;IAClB,OAAO,EAAE,OAAO,CAAC;IACjB,GAAG,EAAE,OAAO,oBAAoB,CAAC;IACjC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,OAAO,EAAE,YAAY,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAChD;AAED,eAAO,MAAM,cAAc,6EAMjB,CAAC;AAEX,eAAO,MAAM,yBAAyB,6EAAiB,CAAC;AA6ExD,wBAAsB,YAAY,IAAI,OAAO,CAAC,cAAc,CAAC,CAE5D;AAED,wBAAsB,oBAAoB,CAAC,MAAM,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAIhF;AAED,wBAAgB,gBAAgB,CAAC,EAAE,GAAE,QAAwB,GAAG,aAAa,CAoB5E;AAED,wBAAsB,kBAAkB,CAAC,MAAM,GAAE,MAAM,EAAwB,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC,CAuBtG;AAED,wBAAsB,kBAAkB,CAAC,MAAM,GAAE,MAAM,EAAwB,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC,CAuBtG;AAED,wBAAsB,kBAAkB,CAAC,MAAM,GAAE,MAAM,EAAwB,GAAG,OAAO,CAAC;IAAE,IAAI,EAAE,UAAU,EAAE,CAAC;IAAC,IAAI,EAAE,UAAU,EAAE,CAAA;CAAE,CAAC,CAKpI;AAED,wBAAgB,kBAAkB,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAQzD"}
1
+ {"version":3,"file":"storage-sync.d.ts","sourceRoot":"","sources":["../../src/db/storage-sync.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE3C,OAAO,EACL,oBAAoB,EAIpB,KAAK,WAAW,EACjB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAKrD,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,GAAG,MAAM,CAAC;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED,MAAM,WAAW,aAAa;IAC5B,UAAU,EAAE,OAAO,CAAC;IACpB,IAAI,EAAE,WAAW,CAAC;IAClB,OAAO,EAAE,OAAO,CAAC;IACjB,GAAG,EAAE,OAAO,oBAAoB,CAAC;IACjC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,OAAO,EAAE,YAAY,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAChD;AAED,eAAO,MAAM,cAAc,6EAMjB,CAAC;AAEX,eAAO,MAAM,yBAAyB,6EAAiB,CAAC;AA6ExD,wBAAsB,YAAY,IAAI,OAAO,CAAC,cAAc,CAAC,CAE5D;AAED,wBAAsB,oBAAoB,CAAC,MAAM,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAIhF;AAED,wBAAgB,gBAAgB,CAAC,EAAE,GAAE,QAAwB,GAAG,aAAa,CAqB5E;AAED,wBAAsB,kBAAkB,CAAC,MAAM,GAAE,MAAM,EAAwB,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC,CAuBtG;AAED,wBAAsB,kBAAkB,CAAC,MAAM,GAAE,MAAM,EAAwB,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC,CAuBtG;AAED,wBAAsB,kBAAkB,CAAC,MAAM,GAAE,MAAM,EAAwB,GAAG,OAAO,CAAC;IAAE,IAAI,EAAE,UAAU,EAAE,CAAC;IAAC,IAAI,EAAE,UAAU,EAAE,CAAA;CAAE,CAAC,CAKpI;AAED,wBAAgB,kBAAkB,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAQzD"}
package/dist/index.d.ts CHANGED
@@ -12,4 +12,6 @@ export { loadConfig, getDataDir, ensureDataDir, DEFAULT_CONFIG, } from "./lib/co
12
12
  export { transcribeAudio, transcribeBuffer, resetClient, } from "./lib/transcriber.js";
13
13
  export { needsEnhancement, enhanceText, processText, resetEnhancementClient, } from "./lib/enhancer.js";
14
14
  export { startRecording, stopRecording, isRecording, getCurrentFile, checkRecordingDeps, recordDuration, } from "./lib/recorder.js";
15
+ export { RecordingsV1Client, RecordingsV1ApiError, } from "./sdk/index.js";
16
+ export type { RecordingsV1ClientOptions, RecordingsV1Recording, RecordingsV1Agent, RecordingsV1Project, RecordingsV1CreateRecordingInput, RecordingsV1RegisterAgentInput, RecordingsV1RegisterProjectInput, } from "./sdk/index.js";
15
17
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,YAAY,EACV,SAAS,EACT,oBAAoB,EACpB,eAAe,EACf,cAAc,EACd,KAAK,EACL,OAAO,EACP,gBAAgB,EAChB,mBAAmB,EACnB,iBAAiB,GAClB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EACL,sBAAsB,EACtB,cAAc,EACd,kBAAkB,EAClB,gBAAgB,GACjB,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EACL,WAAW,EACX,aAAa,EACb,aAAa,EACb,SAAS,EACT,SAAS,GACV,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,EACL,sBAAsB,EACtB,+BAA+B,EAC/B,2BAA2B,EAC3B,oCAAoC,EACpC,oBAAoB,EACpB,gBAAgB,EAChB,gBAAgB,EAChB,0BAA0B,EAC1B,mBAAmB,EACnB,qBAAqB,EACrB,yBAAyB,EACzB,qBAAqB,EACrB,KAAK,aAAa,EAClB,KAAK,UAAU,EACf,KAAK,WAAW,GACjB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EACL,yBAAyB,EACzB,cAAc,EACd,gBAAgB,EAChB,kBAAkB,EAClB,kBAAkB,EAClB,kBAAkB,EAClB,kBAAkB,EAClB,KAAK,aAAa,EAClB,KAAK,UAAU,GAChB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,iBAAiB,EAAE,KAAK,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAG/E,OAAO,EACL,eAAe,EACf,YAAY,EACZ,cAAc,EACd,eAAe,EACf,gBAAgB,EAChB,iBAAiB,GAClB,MAAM,oBAAoB,CAAC;AAG5B,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAGrE,OAAO,EACL,eAAe,EACf,UAAU,EACV,YAAY,GACb,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EACL,UAAU,EACV,UAAU,EACV,aAAa,EACb,cAAc,GACf,MAAM,iBAAiB,CAAC;AAGzB,OAAO,EACL,eAAe,EACf,gBAAgB,EAChB,WAAW,GACZ,MAAM,sBAAsB,CAAC;AAG9B,OAAO,EACL,gBAAgB,EAChB,WAAW,EACX,WAAW,EACX,sBAAsB,GACvB,MAAM,mBAAmB,CAAC;AAG3B,OAAO,EACL,cAAc,EACd,aAAa,EACb,WAAW,EACX,cAAc,EACd,kBAAkB,EAClB,cAAc,GACf,MAAM,mBAAmB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,YAAY,EACV,SAAS,EACT,oBAAoB,EACpB,eAAe,EACf,cAAc,EACd,KAAK,EACL,OAAO,EACP,gBAAgB,EAChB,mBAAmB,EACnB,iBAAiB,GAClB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EACL,sBAAsB,EACtB,cAAc,EACd,kBAAkB,EAClB,gBAAgB,GACjB,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EACL,WAAW,EACX,aAAa,EACb,aAAa,EACb,SAAS,EACT,SAAS,GACV,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,EACL,sBAAsB,EACtB,+BAA+B,EAC/B,2BAA2B,EAC3B,oCAAoC,EACpC,oBAAoB,EACpB,gBAAgB,EAChB,gBAAgB,EAChB,0BAA0B,EAC1B,mBAAmB,EACnB,qBAAqB,EACrB,yBAAyB,EACzB,qBAAqB,EACrB,KAAK,aAAa,EAClB,KAAK,UAAU,EACf,KAAK,WAAW,GACjB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EACL,yBAAyB,EACzB,cAAc,EACd,gBAAgB,EAChB,kBAAkB,EAClB,kBAAkB,EAClB,kBAAkB,EAClB,kBAAkB,EAClB,KAAK,aAAa,EAClB,KAAK,UAAU,GAChB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,iBAAiB,EAAE,KAAK,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAG/E,OAAO,EACL,eAAe,EACf,YAAY,EACZ,cAAc,EACd,eAAe,EACf,gBAAgB,EAChB,iBAAiB,GAClB,MAAM,oBAAoB,CAAC;AAG5B,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAGrE,OAAO,EACL,eAAe,EACf,UAAU,EACV,YAAY,GACb,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EACL,UAAU,EACV,UAAU,EACV,aAAa,EACb,cAAc,GACf,MAAM,iBAAiB,CAAC;AAGzB,OAAO,EACL,eAAe,EACf,gBAAgB,EAChB,WAAW,GACZ,MAAM,sBAAsB,CAAC;AAG9B,OAAO,EACL,gBAAgB,EAChB,WAAW,EACX,WAAW,EACX,sBAAsB,GACvB,MAAM,mBAAmB,CAAC;AAG3B,OAAO,EACL,cAAc,EACd,aAAa,EACb,WAAW,EACX,cAAc,EACd,kBAAkB,EAClB,cAAc,GACf,MAAM,mBAAmB,CAAC;AAG3B,OAAO,EACL,kBAAkB,EAClB,oBAAoB,GACrB,MAAM,gBAAgB,CAAC;AACxB,YAAY,EACV,yBAAyB,EACzB,qBAAqB,EACrB,iBAAiB,EACjB,mBAAmB,EACnB,gCAAgC,EAChC,8BAA8B,EAC9B,gCAAgC,GACjC,MAAM,gBAAgB,CAAC"}
package/dist/index.js CHANGED
@@ -4902,6 +4902,139 @@ var require_lib2 = __commonJS((exports, module) => {
4902
4902
  });
4903
4903
  });
4904
4904
 
4905
+ // src/sdk/v1.generated.ts
4906
+ class ApiError extends Error {
4907
+ status;
4908
+ body;
4909
+ constructor(status, message, body) {
4910
+ super(message);
4911
+ this.status = status;
4912
+ this.body = body;
4913
+ this.name = "ApiError";
4914
+ }
4915
+ }
4916
+
4917
+ class RecordingsV1Client {
4918
+ baseUrl;
4919
+ apiKey;
4920
+ fetchImpl;
4921
+ baseHeaders;
4922
+ constructor(options) {
4923
+ if (!options.baseUrl)
4924
+ throw new Error("RecordingsV1Client requires a baseUrl.");
4925
+ this.baseUrl = options.baseUrl.replace(/\/$/, "");
4926
+ this.apiKey = options.apiKey;
4927
+ this.fetchImpl = options.fetch ?? globalThis.fetch;
4928
+ this.baseHeaders = options.headers ?? {};
4929
+ }
4930
+ async request(method, path, opts) {
4931
+ const url = new URL(this.baseUrl + path);
4932
+ if (opts.query) {
4933
+ for (const [key, value] of Object.entries(opts.query)) {
4934
+ if (value !== undefined && value !== null)
4935
+ url.searchParams.set(key, String(value));
4936
+ }
4937
+ }
4938
+ const headers = { Accept: "application/json", ...this.baseHeaders, ...opts.init?.headers };
4939
+ if (this.apiKey)
4940
+ headers["x-api-key"] = this.apiKey;
4941
+ let payload;
4942
+ if (opts.body !== undefined) {
4943
+ headers["Content-Type"] = "application/json";
4944
+ payload = JSON.stringify(opts.body);
4945
+ }
4946
+ const response = await this.fetchImpl(url.toString(), { ...opts.init, method, headers, body: payload });
4947
+ const text = await response.text();
4948
+ const data = text ? (() => {
4949
+ try {
4950
+ return JSON.parse(text);
4951
+ } catch {
4952
+ return text;
4953
+ }
4954
+ })() : undefined;
4955
+ if (!response.ok) {
4956
+ throw new ApiError(response.status, `${method} ${path} failed: ${response.status}`, data);
4957
+ }
4958
+ return data;
4959
+ }
4960
+ async listAgents(init) {
4961
+ return this.request("GET", `/v1/agents`, {
4962
+ body: undefined,
4963
+ query: undefined,
4964
+ init
4965
+ });
4966
+ }
4967
+ async registerAgent(body, init) {
4968
+ return this.request("POST", `/v1/agents`, {
4969
+ body,
4970
+ query: undefined,
4971
+ init
4972
+ });
4973
+ }
4974
+ async getAgent(id, init) {
4975
+ return this.request("GET", `/v1/agents/${encodeURIComponent(String(id))}`, {
4976
+ body: undefined,
4977
+ query: undefined,
4978
+ init
4979
+ });
4980
+ }
4981
+ async listProjects(init) {
4982
+ return this.request("GET", `/v1/projects`, {
4983
+ body: undefined,
4984
+ query: undefined,
4985
+ init
4986
+ });
4987
+ }
4988
+ async registerProject(body, init) {
4989
+ return this.request("POST", `/v1/projects`, {
4990
+ body,
4991
+ query: undefined,
4992
+ init
4993
+ });
4994
+ }
4995
+ async getProject(id, init) {
4996
+ return this.request("GET", `/v1/projects/${encodeURIComponent(String(id))}`, {
4997
+ body: undefined,
4998
+ query: undefined,
4999
+ init
5000
+ });
5001
+ }
5002
+ async listRecordings(query, init) {
5003
+ return this.request("GET", `/v1/recordings`, {
5004
+ body: undefined,
5005
+ query,
5006
+ init
5007
+ });
5008
+ }
5009
+ async createRecording(body, init) {
5010
+ return this.request("POST", `/v1/recordings`, {
5011
+ body,
5012
+ query: undefined,
5013
+ init
5014
+ });
5015
+ }
5016
+ async getRecording(id, init) {
5017
+ return this.request("GET", `/v1/recordings/${encodeURIComponent(String(id))}`, {
5018
+ body: undefined,
5019
+ query: undefined,
5020
+ init
5021
+ });
5022
+ }
5023
+ async deleteRecording(id, init) {
5024
+ return this.request("DELETE", `/v1/recordings/${encodeURIComponent(String(id))}`, {
5025
+ body: undefined,
5026
+ query: undefined,
5027
+ init
5028
+ });
5029
+ }
5030
+ async getRecordingStats(init) {
5031
+ return this.request("GET", `/v1/stats`, {
5032
+ body: undefined,
5033
+ query: undefined,
5034
+ init
5035
+ });
5036
+ }
5037
+ }
4905
5038
  // src/types/index.ts
4906
5039
  class RecordingNotFoundError extends Error {
4907
5040
  constructor(id) {
@@ -5371,11 +5504,12 @@ class PgAdapterAsync {
5371
5504
  import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
5372
5505
  import { homedir as homedir2 } from "os";
5373
5506
  import { join as join2 } from "path";
5374
- var STORAGE_CONFIG_PATH = join2(homedir2(), ".hasna", "recordings", "storage", "config.json");
5507
+ var LEGACY_DATABASE_CONFIG_KEY = ["r", "d", "s"].join("");
5375
5508
  var RECORDINGS_STORAGE_ENV = "HASNA_RECORDINGS_DATABASE_URL";
5376
5509
  var RECORDINGS_STORAGE_FALLBACK_ENV = "RECORDINGS_DATABASE_URL";
5377
5510
  var RECORDINGS_STORAGE_MODE_ENV = "HASNA_RECORDINGS_STORAGE_MODE";
5378
5511
  var RECORDINGS_STORAGE_MODE_FALLBACK_ENV = "RECORDINGS_STORAGE_MODE";
5512
+ var RECORDINGS_STORAGE_CONFIG_ENV = "HASNA_RECORDINGS_STORAGE_CONFIG";
5379
5513
  var STORAGE_DATABASE_ENV = [RECORDINGS_STORAGE_ENV, RECORDINGS_STORAGE_FALLBACK_ENV];
5380
5514
  var STORAGE_MODE_ENV = [RECORDINGS_STORAGE_MODE_ENV, RECORDINGS_STORAGE_MODE_FALLBACK_ENV];
5381
5515
  function readEnv(name) {
@@ -5403,10 +5537,16 @@ function getStorageDatabaseUrl() {
5403
5537
  const env = getStorageDatabaseEnv();
5404
5538
  return env ? readEnv(env.name) : undefined;
5405
5539
  }
5540
+ function getStorageConfigPath() {
5541
+ const override = readEnv(RECORDINGS_STORAGE_CONFIG_ENV);
5542
+ if (override)
5543
+ return override;
5544
+ return join2(homedir2(), ".hasna", "recordings", "storage", "config.json");
5545
+ }
5406
5546
  function getStorageConfig() {
5407
5547
  const config = {
5408
5548
  mode: "local",
5409
- rds: {
5549
+ postgres: {
5410
5550
  host: "",
5411
5551
  port: 5432,
5412
5552
  username: "",
@@ -5414,11 +5554,13 @@ function getStorageConfig() {
5414
5554
  ssl: true
5415
5555
  }
5416
5556
  };
5417
- if (existsSync2(STORAGE_CONFIG_PATH)) {
5557
+ const storageConfigPath = getStorageConfigPath();
5558
+ if (existsSync2(storageConfigPath)) {
5418
5559
  try {
5419
- const raw = JSON.parse(readFileSync2(STORAGE_CONFIG_PATH, "utf-8"));
5560
+ const raw = JSON.parse(readFileSync2(storageConfigPath, "utf-8"));
5561
+ const legacyDatabaseConfig = typeof raw[LEGACY_DATABASE_CONFIG_KEY] === "object" && raw[LEGACY_DATABASE_CONFIG_KEY] !== null ? raw[LEGACY_DATABASE_CONFIG_KEY] : {};
5420
5562
  config.mode = normalizeMode(raw.mode) ?? config.mode;
5421
- config.rds = { ...config.rds, ...raw.rds ?? {} };
5563
+ config.postgres = { ...config.postgres, ...legacyDatabaseConfig, ...raw.postgres ?? {} };
5422
5564
  } catch {}
5423
5565
  }
5424
5566
  const modeOverride = readEnv(RECORDINGS_STORAGE_MODE_ENV) ?? readEnv(RECORDINGS_STORAGE_MODE_FALLBACK_ENV);
@@ -5435,7 +5577,7 @@ function getStorageConnectionString(dbName = "recordings") {
5435
5577
  if (direct)
5436
5578
  return direct;
5437
5579
  const config = getStorageConfig();
5438
- const { host, port, username, password_env, ssl } = config.rds;
5580
+ const { host, port, username, password_env, ssl } = config.postgres;
5439
5581
  if (!host || !username) {
5440
5582
  throw new Error("Storage database is not configured. Set HASNA_RECORDINGS_DATABASE_URL or configure ~/.hasna/recordings/storage/config.json.");
5441
5583
  }
@@ -5587,8 +5729,9 @@ async function runStorageMigrations(remote) {
5587
5729
  function getStorageStatus(db = getDatabase()) {
5588
5730
  const config = getStorageConfig();
5589
5731
  const activeEnv = getStorageDatabaseEnv();
5732
+ const hasConfiguredPostgres = Boolean(config.postgres.host && config.postgres.username);
5590
5733
  return {
5591
- configured: Boolean(activeEnv),
5734
+ configured: Boolean(activeEnv) || hasConfiguredPostgres,
5592
5735
  mode: config.mode,
5593
5736
  enabled: config.mode === "hybrid" || config.mode === "remote",
5594
5737
  env: STORAGE_DATABASE_ENV,
@@ -6324,6 +6467,8 @@ export {
6324
6467
  STORAGE_TABLES,
6325
6468
  STORAGE_MODE_ENV,
6326
6469
  STORAGE_DATABASE_ENV,
6470
+ RecordingsV1Client,
6471
+ ApiError as RecordingsV1ApiError,
6327
6472
  RecordingNotFoundError,
6328
6473
  RecordingError,
6329
6474
  RECORDINGS_STORAGE_TABLES,
package/dist/mcp/index.js CHANGED
@@ -4920,7 +4920,7 @@ var require_lib2 = __commonJS((exports, module) => {
4920
4920
  var require_package = __commonJS((exports, module) => {
4921
4921
  module.exports = {
4922
4922
  name: "@hasna/recordings",
4923
- version: "0.1.35",
4923
+ version: "0.1.37",
4924
4924
  type: "module",
4925
4925
  description: "Speech-to-text recording tool with MCP and CLI \u2014 records, transcribes, and optionally enhances text using AI",
4926
4926
  repository: {
@@ -4931,7 +4931,8 @@ var require_package = __commonJS((exports, module) => {
4931
4931
  types: "dist/index.d.ts",
4932
4932
  bin: {
4933
4933
  recordings: "dist/cli/index.js",
4934
- "recordings-mcp": "dist/mcp/index.js"
4934
+ "recordings-mcp": "dist/mcp/index.js",
4935
+ "recordings-serve": "dist/server/index.js"
4935
4936
  },
4936
4937
  exports: {
4937
4938
  ".": {
@@ -4941,20 +4942,29 @@ var require_package = __commonJS((exports, module) => {
4941
4942
  "./storage": {
4942
4943
  import: "./dist/storage.js",
4943
4944
  types: "./dist/storage.d.ts"
4945
+ },
4946
+ "./sdk": {
4947
+ import: "./dist/sdk/index.js",
4948
+ types: "./dist/sdk/index.d.ts"
4944
4949
  }
4945
4950
  },
4946
4951
  scripts: {
4947
4952
  clean: "rm -rf dist",
4948
- build: "bun run clean && bun run build:cli && bun run build:mcp && bun run build:lib && tsc --emitDeclarationOnly --outDir dist",
4953
+ build: "bun run clean && bun run build:cli && bun run build:mcp && bun run build:serve && bun run build:lib && tsc --emitDeclarationOnly --outDir dist",
4949
4954
  "build:cli": "bun build src/cli/index.ts --target=bun --outfile=dist/cli/index.js --external=commander --external=chalk --external=openai",
4950
4955
  "build:mcp": "bun build src/mcp/index.ts --target=bun --outfile=dist/mcp/index.js --external=@modelcontextprotocol/sdk --external=openai",
4951
- "build:lib": "bun build src/index.ts src/storage.ts --target=bun --outdir=dist --external=openai",
4956
+ "build:serve": "bun build src/server/index.ts --target=bun --outfile=dist/server/index.js --external=@modelcontextprotocol/sdk --external=@hasna/contracts --external=openai --external=pg",
4957
+ "build:lib": "bun build src/index.ts src/storage.ts src/sdk/index.ts --target=bun --outdir=dist --external=openai",
4958
+ "generate:sdk": "bun run scripts/generate-sdk.ts",
4959
+ migrate: "bun run scripts/migrate.ts",
4952
4960
  typecheck: "tsc --noEmit",
4953
4961
  test: "bun test",
4954
4962
  "test:coverage": "bun test --coverage",
4955
4963
  "dev:cli": "bun run src/cli/index.ts",
4956
4964
  "dev:mcp": "bun run src/mcp/index.ts",
4957
- prepack: "bun run build",
4965
+ "verify:release": "bun run scripts/release-guard.ts",
4966
+ prepack: "bun run build && bun run verify:release",
4967
+ prepublishOnly: "bun run typecheck && bun run test",
4958
4968
  postinstall: "bash scripts/install_macos_app.sh --postinstall"
4959
4969
  },
4960
4970
  files: [
@@ -4970,6 +4980,7 @@ var require_package = __commonJS((exports, module) => {
4970
4980
  "LICENSE"
4971
4981
  ],
4972
4982
  dependencies: {
4983
+ "@hasna/contracts": "0.4.1",
4973
4984
  "@hasna/events": "^0.1.11",
4974
4985
  "@modelcontextprotocol/sdk": "^1.12.1",
4975
4986
  chalk: "^5.4.1",
@@ -9810,17 +9821,18 @@ async function processText(rawText, config, systemPrompt) {
9810
9821
  }
9811
9822
 
9812
9823
  // src/version.ts
9813
- var VERSION = "0.1.35";
9824
+ var VERSION = "0.1.37";
9814
9825
 
9815
9826
  // src/db/storage-config.ts
9816
9827
  import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
9817
9828
  import { homedir as homedir2 } from "os";
9818
9829
  import { join as join2 } from "path";
9819
- var STORAGE_CONFIG_PATH = join2(homedir2(), ".hasna", "recordings", "storage", "config.json");
9830
+ var LEGACY_DATABASE_CONFIG_KEY = ["r", "d", "s"].join("");
9820
9831
  var RECORDINGS_STORAGE_ENV = "HASNA_RECORDINGS_DATABASE_URL";
9821
9832
  var RECORDINGS_STORAGE_FALLBACK_ENV = "RECORDINGS_DATABASE_URL";
9822
9833
  var RECORDINGS_STORAGE_MODE_ENV = "HASNA_RECORDINGS_STORAGE_MODE";
9823
9834
  var RECORDINGS_STORAGE_MODE_FALLBACK_ENV = "RECORDINGS_STORAGE_MODE";
9835
+ var RECORDINGS_STORAGE_CONFIG_ENV = "HASNA_RECORDINGS_STORAGE_CONFIG";
9824
9836
  var STORAGE_DATABASE_ENV = [RECORDINGS_STORAGE_ENV, RECORDINGS_STORAGE_FALLBACK_ENV];
9825
9837
  function readEnv(name) {
9826
9838
  const value = process.env[name]?.trim();
@@ -9847,10 +9859,16 @@ function getStorageDatabaseUrl() {
9847
9859
  const env = getStorageDatabaseEnv();
9848
9860
  return env ? readEnv(env.name) : undefined;
9849
9861
  }
9862
+ function getStorageConfigPath() {
9863
+ const override = readEnv(RECORDINGS_STORAGE_CONFIG_ENV);
9864
+ if (override)
9865
+ return override;
9866
+ return join2(homedir2(), ".hasna", "recordings", "storage", "config.json");
9867
+ }
9850
9868
  function getStorageConfig() {
9851
9869
  const config = {
9852
9870
  mode: "local",
9853
- rds: {
9871
+ postgres: {
9854
9872
  host: "",
9855
9873
  port: 5432,
9856
9874
  username: "",
@@ -9858,11 +9876,13 @@ function getStorageConfig() {
9858
9876
  ssl: true
9859
9877
  }
9860
9878
  };
9861
- if (existsSync2(STORAGE_CONFIG_PATH)) {
9879
+ const storageConfigPath = getStorageConfigPath();
9880
+ if (existsSync2(storageConfigPath)) {
9862
9881
  try {
9863
- const raw = JSON.parse(readFileSync2(STORAGE_CONFIG_PATH, "utf-8"));
9882
+ const raw = JSON.parse(readFileSync2(storageConfigPath, "utf-8"));
9883
+ const legacyDatabaseConfig = typeof raw[LEGACY_DATABASE_CONFIG_KEY] === "object" && raw[LEGACY_DATABASE_CONFIG_KEY] !== null ? raw[LEGACY_DATABASE_CONFIG_KEY] : {};
9864
9884
  config.mode = normalizeMode(raw.mode) ?? config.mode;
9865
- config.rds = { ...config.rds, ...raw.rds ?? {} };
9885
+ config.postgres = { ...config.postgres, ...legacyDatabaseConfig, ...raw.postgres ?? {} };
9866
9886
  } catch {}
9867
9887
  }
9868
9888
  const modeOverride = readEnv(RECORDINGS_STORAGE_MODE_ENV) ?? readEnv(RECORDINGS_STORAGE_MODE_FALLBACK_ENV);
@@ -9879,7 +9899,7 @@ function getStorageConnectionString(dbName = "recordings") {
9879
9899
  if (direct)
9880
9900
  return direct;
9881
9901
  const config = getStorageConfig();
9882
- const { host, port, username, password_env, ssl } = config.rds;
9902
+ const { host, port, username, password_env, ssl } = config.postgres;
9883
9903
  if (!host || !username) {
9884
9904
  throw new Error("Storage database is not configured. Set HASNA_RECORDINGS_DATABASE_URL or configure ~/.hasna/recordings/storage/config.json.");
9885
9905
  }
@@ -10083,8 +10103,9 @@ async function runStorageMigrations(remote) {
10083
10103
  function getStorageStatus(db = getDatabase()) {
10084
10104
  const config = getStorageConfig();
10085
10105
  const activeEnv = getStorageDatabaseEnv();
10106
+ const hasConfiguredPostgres = Boolean(config.postgres.host && config.postgres.username);
10086
10107
  return {
10087
- configured: Boolean(activeEnv),
10108
+ configured: Boolean(activeEnv) || hasConfiguredPostgres,
10088
10109
  mode: config.mode,
10089
10110
  enabled: config.mode === "hybrid" || config.mode === "remote",
10090
10111
  env: STORAGE_DATABASE_ENV,
@@ -0,0 +1,16 @@
1
+ /**
2
+ * @hasna/recordings SDK — typed `/v1` cloud client.
3
+ *
4
+ * Generated from the serve OpenAPI document (src/server/openapi.ts). Regenerate
5
+ * with `bun run generate:sdk`.
6
+ *
7
+ * import { RecordingsV1Client } from "@hasna/recordings/sdk";
8
+ * const client = new RecordingsV1Client({
9
+ * baseUrl: process.env.RECORDINGS_API_URL!,
10
+ * apiKey: process.env.RECORDINGS_API_KEY!,
11
+ * });
12
+ * const { recordings } = await client.listRecordings({ limit: 20 });
13
+ */
14
+ export { RecordingsV1Client, ApiError as RecordingsV1ApiError, } from "./v1.generated.js";
15
+ export type { RecordingsV1ClientOptions, Recording as RecordingsV1Recording, Agent as RecordingsV1Agent, Project as RecordingsV1Project, CreateRecordingInput as RecordingsV1CreateRecordingInput, RegisterAgentInput as RecordingsV1RegisterAgentInput, RegisterProjectInput as RecordingsV1RegisterProjectInput, } from "./v1.generated.js";
16
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/sdk/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,EACL,kBAAkB,EAClB,QAAQ,IAAI,oBAAoB,GACjC,MAAM,mBAAmB,CAAC;AAC3B,YAAY,EACV,yBAAyB,EACzB,SAAS,IAAI,qBAAqB,EAClC,KAAK,IAAI,iBAAiB,EAC1B,OAAO,IAAI,mBAAmB,EAC9B,oBAAoB,IAAI,gCAAgC,EACxD,kBAAkB,IAAI,8BAA8B,EACpD,oBAAoB,IAAI,gCAAgC,GACzD,MAAM,mBAAmB,CAAC"}