@hasna/recordings 0.3.1 → 0.3.8

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.
Files changed (63) hide show
  1. package/README.md +38 -34
  2. package/bun.lock +96 -36
  3. package/dist/__tests__/helpers/installer-guard-execution.d.ts.map +1 -1
  4. package/dist/__tests__/helpers/source-assertions.d.ts +6 -4
  5. package/dist/__tests__/helpers/source-assertions.d.ts.map +1 -1
  6. package/dist/cli/index.js +197 -95
  7. package/dist/cli/macos-shortcut.d.ts +2 -2
  8. package/dist/db/pg-migrations.d.ts +1 -1
  9. package/dist/http/client.d.ts +0 -1
  10. package/dist/http/client.d.ts.map +1 -1
  11. package/dist/index.js +162 -73
  12. package/dist/lib/capture-probe.d.ts +3 -3
  13. package/dist/lib/capture-probe.d.ts.map +1 -1
  14. package/dist/lib/macos-bundle.d.ts +1 -1
  15. package/dist/lib/release-install-policy.d.ts +21 -0
  16. package/dist/lib/release-install-policy.d.ts.map +1 -1
  17. package/dist/mcp/index.js +144 -59
  18. package/dist/sdk/index.d.ts +2 -2
  19. package/dist/sdk/index.js +7 -3
  20. package/dist/sdk/v1.generated.d.ts.map +1 -1
  21. package/dist/server/cloud-config.d.ts +4 -19
  22. package/dist/server/cloud-config.d.ts.map +1 -1
  23. package/dist/server/cloud.d.ts +1 -1
  24. package/dist/server/cloud.d.ts.map +1 -1
  25. package/dist/server/index.js +168 -110
  26. package/dist/server/serve.d.ts.map +1 -1
  27. package/dist/storage.d.ts +1 -1
  28. package/dist/storage.d.ts.map +1 -1
  29. package/dist/storage.js +144 -60
  30. package/dist/store.d.ts.map +1 -1
  31. package/dist/version.d.ts +1 -1
  32. package/dist/version.d.ts.map +1 -1
  33. package/package.json +4 -3
  34. package/packaging/macos/build_release_pkg.sh +10 -4
  35. package/packaging/macos/managed_bootstrap.sh +4 -4
  36. package/packaging/macos/scripts/postinstall +2 -2
  37. package/packaging/macos/scripts/preinstall +2 -0
  38. package/scripts/generate-sdk.ts +17 -16
  39. package/scripts/install_macos_app.sh +75 -28
  40. package/scripts/macos_artifact.ts +162 -45
  41. package/scripts/migrate.ts +2 -2
  42. package/scripts/release-suite-gate.ts +181 -0
  43. package/scripts/set-version.ts +5 -5
  44. package/scripts/smoke_macos_app.sh +80 -34
  45. package/scripts/vacuity-manifests/version-sites.tsv +8 -4
  46. package/src/native/Recordings/App/MenuBarStatusView.swift +9 -4
  47. package/src/native/Recordings/App/RecordingsApp.swift +37 -1
  48. package/src/native/Recordings/RecordingsLib/Info.plist +3 -3
  49. package/src/native/Recordings/RecordingsLib/PermissionRequestLaunchPlan.swift +21 -1
  50. package/src/native/Recordings/RecordingsTests/BarOnlyLaunchPlanTests.swift +99 -0
  51. package/src/native/Recordings/RecordingsTests/CLIRunnerTests.swift +2 -2
  52. package/src/native/Recordings/RecordingsTests/RecordingStartGateTests.swift +1 -1
  53. package/src/native/Recordings/Updater/BootstrapPreflight/BootstrapPreflightMain.swift +1 -1
  54. package/src/native/Recordings/Updater/Broker/ApplicationNamespace.swift +2 -2
  55. package/src/native/Recordings/Updater/Broker/BrokerMain.swift +1 -1
  56. package/src/native/Recordings/Updater/Broker/CanonicalTreeCopy.swift +1 -1
  57. package/src/native/Recordings/Updater/Broker/InstallJournal.swift +1 -1
  58. package/src/native/Recordings/Updater/BrokerTests/ActivationRecoveryPolicyTests.swift +2 -2
  59. package/src/native/Recordings/Updater/Protocol/UpdateProtocol.swift +1 -1
  60. package/src/native/Recordings/Updater/VerifierLauncher/RecordingsVerifierLauncher.c +2 -2
  61. package/src/native/Recordings/build.sh +152 -18
  62. package/dist/lib/retired-deployment-modes.d.ts +0 -24
  63. package/dist/lib/retired-deployment-modes.d.ts.map +0 -1
@@ -17,8 +17,125 @@ var __export = (target, all) => {
17
17
  var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
18
18
  var __require = import.meta.require;
19
19
 
20
+ // package.json
21
+ var package_default;
22
+ var init_package = __esm(() => {
23
+ package_default = {
24
+ name: "@hasna/recordings",
25
+ version: "0.3.8",
26
+ type: "module",
27
+ description: "Speech-to-text recording tool with MCP and CLI \u2014 records, transcribes, and optionally enhances text using AI",
28
+ repository: {
29
+ type: "git",
30
+ url: "git+https://github.com/hasna/apps"
31
+ },
32
+ main: "dist/index.js",
33
+ types: "dist/index.d.ts",
34
+ bin: {
35
+ recordings: "dist/cli/index.js",
36
+ "recordings-mcp": "dist/mcp/index.js",
37
+ "recordings-serve": "dist/server/index.js"
38
+ },
39
+ exports: {
40
+ ".": {
41
+ import: "./dist/index.js",
42
+ types: "./dist/index.d.ts"
43
+ },
44
+ "./storage": {
45
+ import: "./dist/storage.js",
46
+ types: "./dist/storage.d.ts"
47
+ },
48
+ "./sdk": {
49
+ import: "./dist/sdk/index.js",
50
+ types: "./dist/sdk/index.d.ts"
51
+ }
52
+ },
53
+ engines: {
54
+ bun: ">=1.0.0"
55
+ },
56
+ scripts: {
57
+ clean: "rm -rf dist",
58
+ build: "bun run clean && bun run build:cli && bun run build:mcp && bun run build:serve && bun run build:lib && tsc --emitDeclarationOnly --outDir dist",
59
+ "build:cli": "bun build src/cli/index.ts --target=bun --outfile=dist/cli/index.js --external=commander --external=chalk --external=openai",
60
+ "build:mcp": "bun build src/mcp/index.ts --target=bun --outfile=dist/mcp/index.js --external=@modelcontextprotocol/sdk --external=openai",
61
+ "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",
62
+ "build:lib": "bun build src/index.ts src/storage.ts src/sdk/index.ts --target=bun --outdir=dist --external=openai",
63
+ "build:native-fs-guard": "/bin/bash scripts/build_native_fs_guard.sh",
64
+ "generate:sdk": "bun run scripts/generate-sdk.ts",
65
+ migrate: "bun run scripts/migrate.ts",
66
+ typecheck: "tsc --noEmit",
67
+ "typecheck:tcc-contract": "tsc --noEmit -p tsconfig.tcc-contract.json",
68
+ test: "bun test",
69
+ "verify:ci-suite": "bun scripts/ci-linux-suite.ts --check",
70
+ "verify:ci-suite:run": "bun scripts/ci-linux-suite.ts --verify-run",
71
+ "verify:ci-native": "bun scripts/ci-native-build.ts",
72
+ "test:gated": 'bun scripts/ci-linux-suite.ts --check && RECORDINGS_TEST_TIMEOUT_MS="${RECORDINGS_TEST_TIMEOUT_MS:-120000}" bun test --timeout "$RECORDINGS_TEST_TIMEOUT_MS" $(bun scripts/ci-linux-suite.ts --gated)',
73
+ "test:vacuity-battery": 'bun scripts/vacuity-manifest-gen.ts > "${TMPDIR:-/tmp}/vacuity-corrupt-sites.tsv" && bun scripts/vacuity-mutation-battery.ts "${TMPDIR:-/tmp}/vacuity-corrupt-sites.tsv"',
74
+ "test:vacuity-battery:source": "bun scripts/vacuity-mutation-battery.ts scripts/vacuity-manifests/source-side.tsv",
75
+ "test:vacuity-battery:chain": "bun scripts/vacuity-mutation-battery.ts scripts/vacuity-manifests/install-chain.tsv",
76
+ "test:vacuity-battery:vars": "bun scripts/vacuity-mutation-battery.ts scripts/vacuity-manifests/variable-operands.tsv",
77
+ "test:vacuity-battery:reorder": "bun scripts/vacuity-mutation-battery.ts scripts/vacuity-manifests/reorder.tsv",
78
+ "test:coverage": "bun test --coverage",
79
+ "dev:cli": "bun run src/cli/index.ts",
80
+ "desktop:snapshot": "bun run src/cli/index.ts app snapshot",
81
+ "dev:mcp": "bun run src/mcp/index.ts",
82
+ "verify:release": "bun run scripts/release-guard.ts",
83
+ "scan:artifact": "bun run scripts/scan-artifact.ts",
84
+ "version:set": "bun run scripts/set-version.ts",
85
+ "version:check": "bun run scripts/set-version.ts --check",
86
+ prepack: "bun run prepack:platform-gate && bun run version:check && bun run build && bun run verify:release && bun run scan:artifact",
87
+ "prepack:platform-gate": `bash -c 'if [ "$(uname -s)" = Darwin ]; then bun run build:native-fs-guard; else echo "WARN: native fs-guard build skipped on $(uname -s) \u2014 dry-run/CI pack; publish recordings from macOS"; fi'`,
88
+ prepublishOnly: "bun run typecheck && bun run release-suite-gate",
89
+ "release-suite-gate": "bun run scripts/release-suite-gate.ts",
90
+ "typecheck:shortcut-contract": "tsc --noEmit -p tsconfig.test.json"
91
+ },
92
+ files: [
93
+ "dist/",
94
+ "scripts/",
95
+ "Dockerfile.package",
96
+ "bun.lock",
97
+ "src/native/Recordings/App/",
98
+ "src/native/Recordings/RecordingsLib/",
99
+ "src/native/Recordings/RecordingsTests/",
100
+ "src/native/Recordings/Updater/",
101
+ "src/native/Recordings/Package.swift",
102
+ "src/native/Recordings/Package.resolved",
103
+ "src/native/Recordings/build.sh",
104
+ "packaging/macos/",
105
+ "README.md",
106
+ "LICENSE"
107
+ ],
108
+ dependencies: {
109
+ "@hasna/contracts": "0.13.3",
110
+ "@hasna/events": "0.1.11",
111
+ "@modelcontextprotocol/sdk": "^1.12.1",
112
+ chalk: "^5.4.1",
113
+ commander: "^13.1.0",
114
+ openai: "^5.1.0",
115
+ pg: "^8.13.3",
116
+ zod: "^3.24.2"
117
+ },
118
+ devDependencies: {
119
+ "@types/bun": "^1.2.5",
120
+ "@types/pg": "^8.11.11",
121
+ "node-api-headers": "1.9.0",
122
+ typescript: "^5.8.2"
123
+ },
124
+ publishConfig: {
125
+ registry: "https://registry.npmjs.org",
126
+ access: "public"
127
+ },
128
+ license: "Apache-2.0",
129
+ author: "Hasna <andrei@hasna.com>"
130
+ };
131
+ });
132
+
20
133
  // src/version.ts
21
- var VERSION = "0.3.1";
134
+ var VERSION;
135
+ var init_version = __esm(() => {
136
+ init_package();
137
+ VERSION = package_default.version;
138
+ });
22
139
 
23
140
  // src/db/remote-storage.ts
24
141
  import pg from "pg";
@@ -82,59 +199,12 @@ class PgAdapterAsync {
82
199
  }
83
200
  var init_remote_storage = () => {};
84
201
 
85
- // src/lib/retired-deployment-modes.ts
86
- function normalizeModeToken(value) {
87
- return value.trim().toLowerCase().replace(/-/g, "_");
88
- }
89
- function asRetiredDeploymentMode(value) {
90
- const token = normalizeModeToken(value);
91
- return RETIRED_DEPLOYMENT_MODES.includes(token) ? token : null;
92
- }
93
- function retiredDeploymentModeError(rawValue, sourceEnvKey, replacement) {
94
- const mode = asRetiredDeploymentMode(rawValue);
95
- const value = mode === "local" ? replacement.onBox : replacement.offBox;
96
- return new Error(`${sourceEnvKey}=${rawValue} names a deployment mode, and deployment modes are removed: ` + `${RETIRED_DEPLOYMENT_MODES.join(" | ")} no longer select anything. ` + `Set ${replacement.envKey}=${value} instead ` + `(${replacement.envKey} takes ${replacement.onBox} or ${replacement.offBox}).`);
97
- }
98
- var RETIRED_DEPLOYMENT_MODES;
99
- var init_retired_deployment_modes = __esm(() => {
100
- RETIRED_DEPLOYMENT_MODES = [
101
- "local",
102
- "self_hosted",
103
- "cloud",
104
- "remote",
105
- "hybrid"
106
- ];
107
- });
108
-
109
202
  // src/server/cloud-config.ts
110
- function backendReplacement() {
111
- return { envKey: DATA_BACKEND_ENV_KEYS[0], onBox: "sqlite", offBox: "postgresql" };
112
- }
113
- function resolveCloudDatabaseUrl(env = process.env) {
203
+ function resolveDatabaseUrl(env = process.env) {
114
204
  return env.HASNA_RECORDINGS_DATABASE_URL || env.RECORDINGS_DATABASE_URL || env.DATABASE_URL || undefined;
115
205
  }
116
- function configuredDataBackend(env = process.env) {
117
- for (const key of DATA_BACKEND_ENV_KEYS) {
118
- const raw = env[key]?.trim();
119
- if (!raw)
120
- continue;
121
- const token = normalizeModeToken(raw);
122
- if (token === "sqlite")
123
- return { backend: "sqlite", source: key };
124
- if (token === "postgresql" || token === "postgres")
125
- return { backend: "postgresql", source: key };
126
- if (asRetiredDeploymentMode(raw)) {
127
- throw retiredDeploymentModeError(raw, key, backendReplacement());
128
- }
129
- throw new Error(`${key}=${raw} is not a data backend. Use ${DATA_BACKEND_ENV_KEYS[0]}=sqlite or ` + `${DATA_BACKEND_ENV_KEYS[0]}=postgresql.`);
130
- }
131
- return null;
132
- }
133
206
  function resolveDataBackend(env = process.env) {
134
- const configured = configuredDataBackend(env);
135
- if (configured)
136
- return configured.backend;
137
- return resolveCloudDatabaseUrl(env) ? "postgresql" : "sqlite";
207
+ return resolveDatabaseUrl(env) ? "postgresql" : "sqlite";
138
208
  }
139
209
  function isPostgresBackendEnabled(env = process.env) {
140
210
  return resolveDataBackend(env) === "postgresql";
@@ -152,14 +222,6 @@ function requireSigningSecret(env = process.env) {
152
222
  }
153
223
  return signingSecret;
154
224
  }
155
- var DATA_BACKEND_ENV_KEYS;
156
- var init_cloud_config = __esm(() => {
157
- init_retired_deployment_modes();
158
- DATA_BACKEND_ENV_KEYS = [
159
- "HASNA_RECORDINGS_STORAGE_MODE",
160
- "RECORDINGS_STORAGE_MODE"
161
- ];
162
- });
163
225
 
164
226
  // src/server/cloud-readiness.ts
165
227
  var exports_cloud_readiness = {};
@@ -221,7 +283,7 @@ async function assertCloudSchemaContract(pg2) {
221
283
  ON attribute_row.attrelid = constraint_row.conrelid
222
284
  AND attribute_row.attnum = key_row.attnum
223
285
  ORDER BY key_row.position
224
- ) AS columns,
286
+ )::text[] AS columns,
225
287
  referenced_namespace.nspname AS referenced_schema,
226
288
  referenced_table.relname AS referenced_table,
227
289
  CASE WHEN constraint_row.confrelid = 0 THEN ARRAY[]::text[] ELSE ARRAY(
@@ -231,7 +293,7 @@ async function assertCloudSchemaContract(pg2) {
231
293
  ON attribute_row.attrelid = constraint_row.confrelid
232
294
  AND attribute_row.attnum = key_row.attnum
233
295
  ORDER BY key_row.position
234
- ) END AS referenced_columns,
296
+ )::text[] END AS referenced_columns,
235
297
  NULLIF(constraint_row.confdeltype::text, ' ') AS delete_action,
236
298
  NULLIF(constraint_row.confupdtype::text, ' ') AS update_action,
237
299
  NULLIF(constraint_row.confmatchtype::text, ' ') AS match_type
@@ -265,7 +327,7 @@ async function assertCloudSchemaContract(pg2) {
265
327
  AND attribute_row.attnum = key_row.attnum
266
328
  WHERE key_row.position <= index_row.indnkeyatts
267
329
  ORDER BY key_row.position
268
- ) AS columns
330
+ )::text[] AS columns
269
331
  FROM pg_index index_row
270
332
  JOIN pg_class table_row ON table_row.oid = index_row.indrelid
271
333
  JOIN pg_namespace namespace_row ON namespace_row.oid = table_row.relnamespace
@@ -671,8 +733,8 @@ var init_migrate_command = __esm(() => {
671
733
  var exports_cloud = {};
672
734
  __export(exports_cloud, {
673
735
  resolveSigningSecret: () => resolveSigningSecret,
736
+ resolveDatabaseUrl: () => resolveDatabaseUrl,
674
737
  resolveDataBackend: () => resolveDataBackend,
675
- resolveCloudDatabaseUrl: () => resolveCloudDatabaseUrl,
676
738
  requireSigningSecret: () => requireSigningSecret,
677
739
  pingCloudConnectivity: () => pingCloudConnectivity2,
678
740
  pingCloud: () => pingCloud,
@@ -682,7 +744,6 @@ __export(exports_cloud, {
682
744
  getCloudPg: () => getCloudPg,
683
745
  getApiKeyStore: () => getApiKeyStore,
684
746
  ensureCloudSchema: () => ensureCloudSchema,
685
- configuredDataBackend: () => configuredDataBackend,
686
747
  closeCloud: () => closeCloud,
687
748
  RECORDINGS_APP_SLUG: () => RECORDINGS_APP_SLUG
688
749
  });
@@ -691,7 +752,7 @@ import { ApiKeyStore } from "@hasna/contracts/auth";
691
752
  function getCloudPg() {
692
753
  if (cachedPg)
693
754
  return cachedPg;
694
- const url = resolveCloudDatabaseUrl();
755
+ const url = resolveDatabaseUrl();
695
756
  if (!url) {
696
757
  throw new Error("The /v1 API requires a PostgreSQL database URL (HASNA_RECORDINGS_DATABASE_URL / RECORDINGS_DATABASE_URL / DATABASE_URL).");
697
758
  }
@@ -759,10 +820,8 @@ async function closeCloud() {
759
820
  var RECORDINGS_APP_SLUG = "recordings", cachedPg = null, cachedStore = null, cachedVerifier = null, schemaEnsured = null;
760
821
  var init_cloud = __esm(() => {
761
822
  init_remote_storage();
762
- init_cloud_config();
763
823
  init_cloud_readiness();
764
824
  init_migrate_command();
765
- init_cloud_config();
766
825
  });
767
826
 
768
827
  // src/db/errors.ts
@@ -1672,6 +1731,7 @@ function buildV1OpenApiDocument(version = VERSION) {
1672
1731
  }
1673
1732
  var recordingSchema, agentSchema, projectSchema;
1674
1733
  var init_openapi = __esm(() => {
1734
+ init_version();
1675
1735
  recordingSchema = {
1676
1736
  type: "object",
1677
1737
  properties: {
@@ -6727,38 +6787,29 @@ function saveFeedback2(input) {
6727
6787
  }
6728
6788
  var init_feedback = __esm(() => {
6729
6789
  init_database();
6790
+ init_version();
6730
6791
  });
6731
6792
 
6732
6793
  // src/http/client.ts
6733
6794
  function envToken(name) {
6734
6795
  return name.toUpperCase().replace(/-/g, "_");
6735
6796
  }
6736
- function clientStoreReplacement(envKey) {
6737
- return { envKey, onBox: "sqlite", offBox: "http" };
6797
+ function envKeys(name) {
6798
+ const token = envToken(name);
6799
+ return {
6800
+ storeKeys: [`HASNA_${token}_CLIENT_STORE`, `${token}_CLIENT_STORE`],
6801
+ apiUrlKeys: [`HASNA_${token}_API_URL`],
6802
+ apiKeyKeys: [`HASNA_${token}_API_KEY`]
6803
+ };
6738
6804
  }
6739
- function normalizeClientStore(value, sourceEnvKey, replacementEnvKey) {
6740
- const normalized = normalizeModeToken(value);
6805
+ function normalizeClientStore(value) {
6806
+ const normalized = value.trim().toLowerCase();
6741
6807
  if (normalized === "sqlite")
6742
6808
  return "sqlite";
6743
6809
  if (normalized === "http" || normalized === "https")
6744
6810
  return "http";
6745
- if (asRetiredDeploymentMode(value)) {
6746
- throw retiredDeploymentModeError(value, sourceEnvKey, clientStoreReplacement(replacementEnvKey));
6747
- }
6748
6811
  throw new Error(`Unknown client store: ${value}. Use sqlite or http.`);
6749
6812
  }
6750
- function defaultApiBaseUrl(name) {
6751
- return `https://${name}.hasna.xyz`;
6752
- }
6753
- function envKeys(name) {
6754
- const token = envToken(name);
6755
- return {
6756
- storeKeys: [`HASNA_${token}_CLIENT_STORE`, `${token}_CLIENT_STORE`],
6757
- retiredModeKeys: [`HASNA_${token}_STORAGE_MODE`, `HASNA_${token}_MODE`, `${token}_STORAGE_MODE`, `${token}_MODE`],
6758
- apiUrlKeys: [`HASNA_${token}_API_URL`, `${token}_API_URL`],
6759
- apiKeyKeys: [`HASNA_${token}_API_KEY`, `${token}_API_KEY`]
6760
- };
6761
- }
6762
6813
  function firstEnv(env, keys) {
6763
6814
  for (const key of keys) {
6764
6815
  const value = env[key]?.trim();
@@ -6767,20 +6818,6 @@ function firstEnv(env, keys) {
6767
6818
  }
6768
6819
  return null;
6769
6820
  }
6770
- function assertNoRetiredMode(env, keys) {
6771
- for (const key of keys.retiredModeKeys) {
6772
- const value = env[key]?.trim();
6773
- if (!value)
6774
- continue;
6775
- const normalized = normalizeModeToken(value);
6776
- if (SERVER_BACKEND_VALUES.includes(normalized))
6777
- continue;
6778
- if (asRetiredDeploymentMode(value)) {
6779
- throw retiredDeploymentModeError(value, key, clientStoreReplacement(keys.storeKeys[0]));
6780
- }
6781
- throw new Error(`${key}=${value} is not a client store. ${key} no longer selects one; ` + `set ${keys.storeKeys[0]}=sqlite or ${keys.storeKeys[0]}=http instead.`);
6782
- }
6783
- }
6784
6821
  function toV1BaseUrl(apiUrl) {
6785
6822
  const url = new URL(apiUrl);
6786
6823
  if (url.protocol !== "http:" && url.protocol !== "https:") {
@@ -6796,22 +6833,44 @@ function toV1BaseUrl(apiUrl) {
6796
6833
  }
6797
6834
  function resolveTransport(name, env = process.env) {
6798
6835
  const keys = envKeys(name);
6799
- assertNoRetiredMode(env, keys);
6800
6836
  const storeHit = firstEnv(env, keys.storeKeys);
6801
6837
  const urlHit = firstEnv(env, keys.apiUrlKeys);
6802
6838
  const keyHit = firstEnv(env, keys.apiKeyKeys);
6803
6839
  let requested = "sqlite";
6804
6840
  let modeSource = "default";
6805
6841
  if (storeHit) {
6806
- requested = normalizeClientStore(storeHit.value, storeHit.key, keys.storeKeys[0]);
6842
+ requested = normalizeClientStore(storeHit.value);
6807
6843
  modeSource = storeHit.key;
6808
6844
  } else if (urlHit && keyHit) {
6809
6845
  requested = "http";
6810
6846
  modeSource = "auto:api-url+api-key";
6847
+ } else if (urlHit || keyHit) {
6848
+ const missing = urlHit ? keys.apiKeyKeys[0] : keys.apiUrlKeys[0];
6849
+ const present = urlHit ? keys.apiUrlKeys[0] : keys.apiKeyKeys[0];
6850
+ return {
6851
+ transport: "sqlite",
6852
+ requested,
6853
+ modeSource,
6854
+ baseUrl: null,
6855
+ apiKeyPresent: Boolean(keyHit),
6856
+ misconfigured: true,
6857
+ warning: `${present} is set but ${missing} is not: the hosted API is only ` + `selected when BOTH are present. Set ${missing}, or unset ${present} to ` + `use the on-box store.`
6858
+ };
6811
6859
  }
6812
6860
  if (requested === "sqlite") {
6813
6861
  return { transport: "sqlite", requested, modeSource, baseUrl: null, apiKeyPresent: Boolean(keyHit), misconfigured: false, warning: null };
6814
6862
  }
6863
+ if (!urlHit) {
6864
+ return {
6865
+ transport: "sqlite",
6866
+ requested,
6867
+ modeSource,
6868
+ baseUrl: null,
6869
+ apiKeyPresent: Boolean(keyHit),
6870
+ misconfigured: true,
6871
+ warning: `${modeSource}=http but no API URL is set (${keys.apiUrlKeys[0]}). Refusing to route to the API.`
6872
+ };
6873
+ }
6815
6874
  if (!keyHit) {
6816
6875
  return {
6817
6876
  transport: "sqlite",
@@ -6823,7 +6882,7 @@ function resolveTransport(name, env = process.env) {
6823
6882
  warning: `${modeSource}=http but no API key is set (${keys.apiKeyKeys[0]}). Refusing to route to the API.`
6824
6883
  };
6825
6884
  }
6826
- const rawUrl = urlHit?.value ?? defaultApiBaseUrl(name);
6885
+ const rawUrl = urlHit.value;
6827
6886
  let baseUrl;
6828
6887
  try {
6829
6888
  baseUrl = toV1BaseUrl(rawUrl);
@@ -7010,10 +7069,8 @@ function resolveStorageClient(name, env = process.env, fetchImpl) {
7010
7069
  const transport = createHttpTransport({ name, baseUrl: resolution.baseUrl, apiKey, ...fetchImpl ? { fetchImpl } : {} });
7011
7070
  return { transport: "http", client: createStorageClient(name, transport), resolution };
7012
7071
  }
7013
- var SERVER_BACKEND_VALUES, HasnaHttpError, RETRY_STATUSES, IDEMPOTENT, defaultSleep = (ms) => new Promise((r) => setTimeout(r, ms));
7072
+ var HasnaHttpError, RETRY_STATUSES, IDEMPOTENT, defaultSleep = (ms) => new Promise((r) => setTimeout(r, ms));
7014
7073
  var init_client = __esm(() => {
7015
- init_retired_deployment_modes();
7016
- SERVER_BACKEND_VALUES = ["sqlite", "postgresql", "postgres"];
7017
7074
  HasnaHttpError = class HasnaHttpError extends Error {
7018
7075
  status;
7019
7076
  method;
@@ -8229,6 +8286,7 @@ var init_mcp = __esm(async () => {
8229
8286
  init_store();
8230
8287
  init_transcriber();
8231
8288
  init_enhancer();
8289
+ init_version();
8232
8290
  init_machine();
8233
8291
  config = loadConfig();
8234
8292
  ensureDataDir(config);
@@ -8371,7 +8429,7 @@ async function startServer(port, options) {
8371
8429
  }
8372
8430
  var SECURITY_HEADERS, rateLimitMap, RATE_LIMIT_WINDOW_MS = 60000, RATE_LIMIT_MAX;
8373
8431
  var init_serve = __esm(() => {
8374
- init_cloud_config();
8432
+ init_version();
8375
8433
  init_v1();
8376
8434
  init_openapi();
8377
8435
  SECURITY_HEADERS = {
@@ -8385,6 +8443,7 @@ var init_serve = __esm(() => {
8385
8443
  });
8386
8444
 
8387
8445
  // src/server/index.ts
8446
+ init_version();
8388
8447
  var DEFAULT_PORT = 8874;
8389
8448
  function parsePort() {
8390
8449
  const arg = process.argv.find((a) => a === "--port" || a.startsWith("--port="));
@@ -8421,8 +8480,7 @@ Commands:
8421
8480
  migrate Apply the PostgreSQL schema, then exit. Idempotent.
8422
8481
 
8423
8482
  Environment:
8424
- HASNA_RECORDINGS_STORAGE_MODE Data backend: sqlite | postgresql
8425
- HASNA_RECORDINGS_DATABASE_URL PostgreSQL DSN (implies postgresql)
8483
+ HASNA_RECORDINGS_DATABASE_URL PostgreSQL DSN (present -> postgresql backend, else sqlite)
8426
8484
  HASNA_RECORDINGS_API_SIGNING_KEY HMAC signing secret for API-key auth`);
8427
8485
  }
8428
8486
  async function runMigrate() {
@@ -8431,11 +8489,11 @@ async function runMigrate() {
8431
8489
  getCloudPg: getCloudPg2,
8432
8490
  migrateCloudSchema: migrateCloudSchema2,
8433
8491
  pingCloudConnectivity: pingCloudConnectivity3,
8434
- resolveCloudDatabaseUrl: resolveCloudDatabaseUrl2
8492
+ resolveDatabaseUrl: resolveDatabaseUrl2
8435
8493
  } = await Promise.resolve().then(() => (init_cloud(), exports_cloud));
8436
8494
  const { assertCloudSchemaContract: assertCloudSchemaContract2 } = await Promise.resolve().then(() => (init_cloud_readiness(), exports_cloud_readiness));
8437
8495
  const { runCloudMigration: runCloudMigration2 } = await Promise.resolve().then(() => (init_migrate_command(), exports_migrate_command));
8438
- if (!resolveCloudDatabaseUrl2()) {
8496
+ if (!resolveDatabaseUrl2()) {
8439
8497
  console.error("migrate: no database URL (HASNA_RECORDINGS_DATABASE_URL / RECORDINGS_DATABASE_URL / DATABASE_URL)");
8440
8498
  process.exit(2);
8441
8499
  }
@@ -1 +1 @@
1
- {"version":3,"file":"serve.d.ts","sourceRoot":"","sources":["../../src/server/serve.ts"],"names":[],"mappings":"AAqBA,eAAO,MAAM,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAKnD,CAAC;AAyCF,MAAM,WAAW,kBAAkB;IACjC,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,iBAAiB;IAChC,cAAc,CAAC,EAAE,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAClD,SAAS,CAAC,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;IACnC,QAAQ,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAC;CACzC;AAED,wBAAgB,UAAU,CAAC,OAAO,GAAE,iBAAsB,IAWtD,KAAK,OAAO,EACZ,QAAQ;IAAE,SAAS,CAAC,GAAG,EAAE,OAAO,GAAG;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAA;CAAE,KAC9D,OAAO,CAAC,QAAQ,CAAC,CAqFrB;AAED,wBAAsB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAAC,UAAU,CAAC,OAAO,GAAG,CAAC,KAAK,CAAC,CAAC,CAqBnH"}
1
+ {"version":3,"file":"serve.d.ts","sourceRoot":"","sources":["../../src/server/serve.ts"],"names":[],"mappings":"AAsBA,eAAO,MAAM,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAKnD,CAAC;AAyCF,MAAM,WAAW,kBAAkB;IACjC,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,iBAAiB;IAChC,cAAc,CAAC,EAAE,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAClD,SAAS,CAAC,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;IACnC,QAAQ,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAC;CACzC;AAED,wBAAgB,UAAU,CAAC,OAAO,GAAE,iBAAsB,IAWtD,KAAK,OAAO,EACZ,QAAQ;IAAE,SAAS,CAAC,GAAG,EAAE,OAAO,GAAG;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAA;CAAE,KAC9D,OAAO,CAAC,QAAQ,CAAC,CAqFrB;AAED,wBAAsB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAAC,UAAU,CAAC,OAAO,GAAG,CAAC,KAAK,CAAC,CAAC,CAqBnH"}
package/dist/storage.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  export { getStore, __resetStore, APP } from "./store.js";
2
2
  export type { Store, RecordingStats, FeedbackInput } from "./store.js";
3
- export { resolveStorageClient, resolveTransport, createHttpTransport, createStorageClient, toV1BaseUrl, defaultApiBaseUrl, HasnaHttpError, } from "./http/client.js";
3
+ export { resolveStorageClient, resolveTransport, createHttpTransport, createStorageClient, toV1BaseUrl, HasnaHttpError, } from "./http/client.js";
4
4
  export type { StorageClient, ClientStore, TransportKind, TransportResolution, HttpTransport, } from "./http/client.js";
5
5
  //# sourceMappingURL=storage.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../src/storage.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,GAAG,EAAE,MAAM,YAAY,CAAC;AACzD,YAAY,EAAE,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEvE,OAAO,EACL,oBAAoB,EACpB,gBAAgB,EAChB,mBAAmB,EACnB,mBAAmB,EACnB,WAAW,EACX,iBAAiB,EACjB,cAAc,GACf,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EACV,aAAa,EACb,WAAW,EACX,aAAa,EACb,mBAAmB,EACnB,aAAa,GACd,MAAM,kBAAkB,CAAC"}
1
+ {"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../src/storage.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,GAAG,EAAE,MAAM,YAAY,CAAC;AACzD,YAAY,EAAE,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEvE,OAAO,EACL,oBAAoB,EACpB,gBAAgB,EAChB,mBAAmB,EACnB,mBAAmB,EACnB,WAAW,EACX,cAAc,GACf,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EACV,aAAa,EACb,WAAW,EACX,aAAa,EACb,mBAAmB,EACnB,aAAa,GACd,MAAM,kBAAkB,CAAC"}