@hasna/recordings 0.3.2 → 0.3.9
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 +38 -34
- package/bun.lock +96 -36
- package/dist/__tests__/helpers/source-assertions.d.ts +6 -4
- package/dist/__tests__/helpers/source-assertions.d.ts.map +1 -1
- package/dist/cli/index.js +1059 -219
- package/dist/cli/macos-shortcut.d.ts +2 -2
- package/dist/db/pg-migrations.d.ts +1 -1
- package/dist/http/client.d.ts +6 -14
- package/dist/http/client.d.ts.map +1 -1
- package/dist/index.js +1971 -175
- package/dist/lib/capture-probe.d.ts +3 -3
- package/dist/lib/capture-probe.d.ts.map +1 -1
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/macos-bundle.d.ts +1 -1
- package/dist/lib/release-install-policy.d.ts +21 -0
- package/dist/lib/release-install-policy.d.ts.map +1 -1
- package/dist/mcp/index.js +978 -142
- package/dist/sdk/index.d.ts +2 -2
- package/dist/sdk/index.js +7 -3
- package/dist/sdk/v1.generated.d.ts.map +1 -1
- package/dist/server/cloud-config.d.ts +4 -19
- package/dist/server/cloud-config.d.ts.map +1 -1
- package/dist/server/cloud.d.ts +1 -1
- package/dist/server/cloud.d.ts.map +1 -1
- package/dist/server/index.js +217 -299
- package/dist/server/serve.d.ts.map +1 -1
- package/dist/storage.d.ts +1 -1
- package/dist/storage.d.ts.map +1 -1
- package/dist/storage.js +1881 -90
- package/dist/store.d.ts.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.d.ts.map +1 -1
- package/package.json +4 -3
- package/packaging/macos/build_release_pkg.sh +10 -4
- package/packaging/macos/managed_bootstrap.sh +4 -4
- package/packaging/macos/scripts/postinstall +2 -2
- package/packaging/macos/scripts/preinstall +2 -0
- package/scripts/generate-sdk.ts +17 -16
- package/scripts/install_macos_app.sh +22 -22
- package/scripts/macos_artifact.ts +48 -39
- package/scripts/migrate.ts +2 -2
- package/scripts/release-suite-gate.ts +174 -0
- package/scripts/set-version.ts +5 -5
- package/scripts/smoke_macos_app.sh +21 -21
- package/scripts/vacuity-manifests/version-sites.tsv +8 -4
- package/src/native/Recordings/RecordingsLib/Info.plist +3 -3
- package/src/native/Recordings/RecordingsTests/CLIRunnerTests.swift +2 -2
- package/src/native/Recordings/RecordingsTests/RecordingStartGateTests.swift +1 -1
- package/src/native/Recordings/Updater/BootstrapPreflight/BootstrapPreflightMain.swift +1 -1
- package/src/native/Recordings/Updater/Broker/ApplicationNamespace.swift +2 -2
- package/src/native/Recordings/Updater/Broker/BrokerMain.swift +1 -1
- package/src/native/Recordings/Updater/Broker/CanonicalTreeCopy.swift +1 -1
- package/src/native/Recordings/Updater/Broker/InstallJournal.swift +1 -1
- package/src/native/Recordings/Updater/BrokerTests/ActivationRecoveryPolicyTests.swift +2 -2
- package/src/native/Recordings/Updater/Protocol/UpdateProtocol.swift +1 -1
- package/src/native/Recordings/Updater/VerifierLauncher/RecordingsVerifierLauncher.c +2 -2
- package/src/native/Recordings/build.sh +14 -20
- package/dist/lib/retired-deployment-modes.d.ts +0 -24
- package/dist/lib/retired-deployment-modes.d.ts.map +0 -1
package/dist/server/index.js
CHANGED
|
@@ -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.9",
|
|
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.4",
|
|
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
|
|
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
|
|
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
|
-
|
|
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 =
|
|
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,34 @@ 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
|
|
6794
|
+
import { createClientTransport } from "@hasna/contracts/client";
|
|
6795
|
+
import {
|
|
6796
|
+
createHasnaStorageClient,
|
|
6797
|
+
resolveStorageClient
|
|
6798
|
+
} from "@hasna/contracts/client/storage";
|
|
6733
6799
|
function envToken(name) {
|
|
6734
6800
|
return name.toUpperCase().replace(/-/g, "_");
|
|
6735
6801
|
}
|
|
6736
|
-
function
|
|
6737
|
-
|
|
6802
|
+
function envKeys(name) {
|
|
6803
|
+
const token = envToken(name);
|
|
6804
|
+
return {
|
|
6805
|
+
storeKeys: [`HASNA_${token}_CLIENT_STORE`, `${token}_CLIENT_STORE`],
|
|
6806
|
+
apiUrlKeys: [`HASNA_${token}_API_URL`],
|
|
6807
|
+
apiKeyKeys: [`HASNA_${token}_API_KEY`]
|
|
6808
|
+
};
|
|
6738
6809
|
}
|
|
6739
|
-
function normalizeClientStore(value
|
|
6740
|
-
const normalized =
|
|
6810
|
+
function normalizeClientStore(value) {
|
|
6811
|
+
const normalized = value.trim().toLowerCase();
|
|
6741
6812
|
if (normalized === "sqlite")
|
|
6742
6813
|
return "sqlite";
|
|
6743
6814
|
if (normalized === "http" || normalized === "https")
|
|
6744
6815
|
return "http";
|
|
6745
|
-
if (asRetiredDeploymentMode(value)) {
|
|
6746
|
-
throw retiredDeploymentModeError(value, sourceEnvKey, clientStoreReplacement(replacementEnvKey));
|
|
6747
|
-
}
|
|
6748
6816
|
throw new Error(`Unknown client store: ${value}. Use sqlite or http.`);
|
|
6749
6817
|
}
|
|
6750
|
-
function defaultApiBaseUrl(name) {
|
|
6751
|
-
return `http://localhost:8874`;
|
|
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
6818
|
function firstEnv(env, keys) {
|
|
6763
6819
|
for (const key of keys) {
|
|
6764
6820
|
const value = env[key]?.trim();
|
|
@@ -6767,20 +6823,6 @@ function firstEnv(env, keys) {
|
|
|
6767
6823
|
}
|
|
6768
6824
|
return null;
|
|
6769
6825
|
}
|
|
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
6826
|
function toV1BaseUrl(apiUrl) {
|
|
6785
6827
|
const url = new URL(apiUrl);
|
|
6786
6828
|
if (url.protocol !== "http:" && url.protocol !== "https:") {
|
|
@@ -6796,22 +6838,44 @@ function toV1BaseUrl(apiUrl) {
|
|
|
6796
6838
|
}
|
|
6797
6839
|
function resolveTransport(name, env = process.env) {
|
|
6798
6840
|
const keys = envKeys(name);
|
|
6799
|
-
assertNoRetiredMode(env, keys);
|
|
6800
6841
|
const storeHit = firstEnv(env, keys.storeKeys);
|
|
6801
6842
|
const urlHit = firstEnv(env, keys.apiUrlKeys);
|
|
6802
6843
|
const keyHit = firstEnv(env, keys.apiKeyKeys);
|
|
6803
6844
|
let requested = "sqlite";
|
|
6804
6845
|
let modeSource = "default";
|
|
6805
6846
|
if (storeHit) {
|
|
6806
|
-
requested = normalizeClientStore(storeHit.value
|
|
6847
|
+
requested = normalizeClientStore(storeHit.value);
|
|
6807
6848
|
modeSource = storeHit.key;
|
|
6808
6849
|
} else if (urlHit && keyHit) {
|
|
6809
6850
|
requested = "http";
|
|
6810
6851
|
modeSource = "auto:api-url+api-key";
|
|
6852
|
+
} else if (urlHit || keyHit) {
|
|
6853
|
+
const missing = urlHit ? keys.apiKeyKeys[0] : keys.apiUrlKeys[0];
|
|
6854
|
+
const present = urlHit ? keys.apiUrlKeys[0] : keys.apiKeyKeys[0];
|
|
6855
|
+
return {
|
|
6856
|
+
transport: "sqlite",
|
|
6857
|
+
requested,
|
|
6858
|
+
modeSource,
|
|
6859
|
+
baseUrl: null,
|
|
6860
|
+
apiKeyPresent: Boolean(keyHit),
|
|
6861
|
+
misconfigured: true,
|
|
6862
|
+
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.`
|
|
6863
|
+
};
|
|
6811
6864
|
}
|
|
6812
6865
|
if (requested === "sqlite") {
|
|
6813
6866
|
return { transport: "sqlite", requested, modeSource, baseUrl: null, apiKeyPresent: Boolean(keyHit), misconfigured: false, warning: null };
|
|
6814
6867
|
}
|
|
6868
|
+
if (!urlHit) {
|
|
6869
|
+
return {
|
|
6870
|
+
transport: "sqlite",
|
|
6871
|
+
requested,
|
|
6872
|
+
modeSource,
|
|
6873
|
+
baseUrl: null,
|
|
6874
|
+
apiKeyPresent: Boolean(keyHit),
|
|
6875
|
+
misconfigured: true,
|
|
6876
|
+
warning: `${modeSource}=http but no API URL is set (${keys.apiUrlKeys[0]}). Refusing to route to the API.`
|
|
6877
|
+
};
|
|
6878
|
+
}
|
|
6815
6879
|
if (!keyHit) {
|
|
6816
6880
|
return {
|
|
6817
6881
|
transport: "sqlite",
|
|
@@ -6823,7 +6887,7 @@ function resolveTransport(name, env = process.env) {
|
|
|
6823
6887
|
warning: `${modeSource}=http but no API key is set (${keys.apiKeyKeys[0]}). Refusing to route to the API.`
|
|
6824
6888
|
};
|
|
6825
6889
|
}
|
|
6826
|
-
const rawUrl = urlHit
|
|
6890
|
+
const rawUrl = urlHit.value;
|
|
6827
6891
|
let baseUrl;
|
|
6828
6892
|
try {
|
|
6829
6893
|
baseUrl = toV1BaseUrl(rawUrl);
|
|
@@ -6833,201 +6897,38 @@ function resolveTransport(name, env = process.env) {
|
|
|
6833
6897
|
}
|
|
6834
6898
|
return { transport: "http", requested, modeSource, baseUrl, apiKeyPresent: true, misconfigured: false, warning: null };
|
|
6835
6899
|
}
|
|
6836
|
-
function
|
|
6837
|
-
if (!query)
|
|
6838
|
-
return path;
|
|
6839
|
-
const params = new URLSearchParams;
|
|
6840
|
-
for (const [key, value] of Object.entries(query)) {
|
|
6841
|
-
if (value === null || value === undefined)
|
|
6842
|
-
continue;
|
|
6843
|
-
if (Array.isArray(value))
|
|
6844
|
-
for (const v of value)
|
|
6845
|
-
params.append(key, String(v));
|
|
6846
|
-
else
|
|
6847
|
-
params.append(key, String(value));
|
|
6848
|
-
}
|
|
6849
|
-
const qs = params.toString();
|
|
6850
|
-
return qs ? `${path}${path.includes("?") ? "&" : "?"}${qs}` : path;
|
|
6851
|
-
}
|
|
6852
|
-
function createHttpTransport(options) {
|
|
6853
|
-
const fetchImpl = options.fetchImpl ?? ((input, init) => fetch(input, init));
|
|
6854
|
-
const base = options.baseUrl.replace(/\/+$/, "");
|
|
6855
|
-
const timeoutMs = options.timeoutMs ?? 30000;
|
|
6856
|
-
const sleep = options.sleepImpl ?? defaultSleep;
|
|
6857
|
-
async function once(method, rel, url, body, opts) {
|
|
6858
|
-
const headers = {
|
|
6859
|
-
"x-api-key": options.apiKey,
|
|
6860
|
-
Authorization: `Bearer ${options.apiKey}`,
|
|
6861
|
-
Accept: "application/json",
|
|
6862
|
-
...opts.headers ?? {}
|
|
6863
|
-
};
|
|
6864
|
-
if (opts.idempotencyKey)
|
|
6865
|
-
headers["Idempotency-Key"] = opts.idempotencyKey;
|
|
6866
|
-
const init = { method, headers };
|
|
6867
|
-
if (body !== undefined) {
|
|
6868
|
-
headers["Content-Type"] = "application/json";
|
|
6869
|
-
init.body = JSON.stringify(body);
|
|
6870
|
-
}
|
|
6871
|
-
const controller = new AbortController;
|
|
6872
|
-
const onAbort = () => controller.abort();
|
|
6873
|
-
if (opts.signal) {
|
|
6874
|
-
if (opts.signal.aborted)
|
|
6875
|
-
controller.abort();
|
|
6876
|
-
else
|
|
6877
|
-
opts.signal.addEventListener("abort", onAbort, { once: true });
|
|
6878
|
-
}
|
|
6879
|
-
const timer = setTimeout(() => controller.abort(), opts.timeoutMs ?? timeoutMs);
|
|
6880
|
-
init.signal = controller.signal;
|
|
6881
|
-
let response;
|
|
6882
|
-
try {
|
|
6883
|
-
response = await fetchImpl(url, init);
|
|
6884
|
-
} catch (error2) {
|
|
6885
|
-
const err = error2 instanceof Error ? error2 : new Error(String(error2));
|
|
6886
|
-
if (opts.signal?.aborted)
|
|
6887
|
-
return { ok: false, retryable: false, error: err };
|
|
6888
|
-
return { ok: false, retryable: true, error: err };
|
|
6889
|
-
} finally {
|
|
6890
|
-
clearTimeout(timer);
|
|
6891
|
-
if (opts.signal)
|
|
6892
|
-
opts.signal.removeEventListener("abort", onAbort);
|
|
6893
|
-
}
|
|
6894
|
-
const text = await response.text();
|
|
6895
|
-
let parsed = undefined;
|
|
6896
|
-
if (text.length > 0) {
|
|
6897
|
-
try {
|
|
6898
|
-
parsed = JSON.parse(text);
|
|
6899
|
-
} catch {
|
|
6900
|
-
parsed = text;
|
|
6901
|
-
}
|
|
6902
|
-
}
|
|
6903
|
-
if (!response.ok) {
|
|
6904
|
-
return { ok: false, retryable: RETRY_STATUSES.has(response.status), error: new HasnaHttpError(method, rel, response.status, parsed) };
|
|
6905
|
-
}
|
|
6906
|
-
return { ok: true, value: parsed };
|
|
6907
|
-
}
|
|
6908
|
-
async function request(method, path, body, opts = {}) {
|
|
6909
|
-
const upper = method.toUpperCase();
|
|
6910
|
-
const rel = appendQuery(path.startsWith("/") ? path : `/${path}`, opts.query);
|
|
6911
|
-
const url = `${base}${rel}`;
|
|
6912
|
-
const methodRetryable = IDEMPOTENT.has(upper) || Boolean(opts.idempotencyKey);
|
|
6913
|
-
const maxRetries = opts.retries ?? 2;
|
|
6914
|
-
const maxAttempts = methodRetryable ? maxRetries + 1 : 1;
|
|
6915
|
-
let last = null;
|
|
6916
|
-
for (let attempt = 1;attempt <= maxAttempts; attempt++) {
|
|
6917
|
-
const result = await once(upper, rel, url, body, opts);
|
|
6918
|
-
if (result.ok)
|
|
6919
|
-
return result.value;
|
|
6920
|
-
last = result;
|
|
6921
|
-
const canRetry = methodRetryable && result.retryable && attempt < maxAttempts;
|
|
6922
|
-
if (!canRetry)
|
|
6923
|
-
break;
|
|
6924
|
-
const backoff = Math.min(2000, 200 * 2 ** (attempt - 1));
|
|
6925
|
-
const jitter = Math.floor(Math.random() * (backoff / 2 + 1));
|
|
6926
|
-
await sleep(backoff + jitter);
|
|
6927
|
-
}
|
|
6928
|
-
if (last === null)
|
|
6929
|
-
throw new Error(`Request to ${rel} completed without a result`);
|
|
6930
|
-
throw last.error;
|
|
6931
|
-
}
|
|
6932
|
-
return {
|
|
6933
|
-
baseUrl: base,
|
|
6934
|
-
request,
|
|
6935
|
-
get: (path, opts) => request("GET", path, undefined, opts),
|
|
6936
|
-
post: (path, body, opts) => request("POST", path, body, opts),
|
|
6937
|
-
patch: (path, body, opts) => request("PATCH", path, body, opts),
|
|
6938
|
-
put: (path, body, opts) => request("PUT", path, body, opts),
|
|
6939
|
-
del: (path, body, opts) => request("DELETE", path, body, opts)
|
|
6940
|
-
};
|
|
6941
|
-
}
|
|
6942
|
-
function newIdempotencyKey() {
|
|
6943
|
-
const g = globalThis;
|
|
6944
|
-
if (g.crypto?.randomUUID)
|
|
6945
|
-
return g.crypto.randomUUID();
|
|
6946
|
-
return `idmp_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 12)}`;
|
|
6947
|
-
}
|
|
6948
|
-
function extractItems(raw, extraKeys = []) {
|
|
6949
|
-
if (Array.isArray(raw))
|
|
6950
|
-
return raw;
|
|
6951
|
-
if (raw && typeof raw === "object") {
|
|
6952
|
-
const obj = raw;
|
|
6953
|
-
for (const key of [...extraKeys, "items", "data", "results", "rows", "records"]) {
|
|
6954
|
-
if (Array.isArray(obj[key]))
|
|
6955
|
-
return obj[key];
|
|
6956
|
-
}
|
|
6957
|
-
}
|
|
6958
|
-
return [];
|
|
6959
|
-
}
|
|
6960
|
-
function createStorageClient(name, transport) {
|
|
6961
|
-
const rp = (r) => `/${r.replace(/^\/+|\/+$/g, "")}`;
|
|
6962
|
-
const ep = (r, id) => `${rp(r)}/${encodeURIComponent(String(id))}`;
|
|
6963
|
-
return {
|
|
6964
|
-
name,
|
|
6965
|
-
baseUrl: transport.baseUrl,
|
|
6966
|
-
transport,
|
|
6967
|
-
async list(resource, query) {
|
|
6968
|
-
const raw = await transport.get(rp(resource), { query });
|
|
6969
|
-
return { items: extractItems(raw, [resource]), raw };
|
|
6970
|
-
},
|
|
6971
|
-
async get(resource, id) {
|
|
6972
|
-
try {
|
|
6973
|
-
return await transport.get(ep(resource, id));
|
|
6974
|
-
} catch (error2) {
|
|
6975
|
-
if (error2 instanceof HasnaHttpError && error2.status === 404)
|
|
6976
|
-
return null;
|
|
6977
|
-
throw error2;
|
|
6978
|
-
}
|
|
6979
|
-
},
|
|
6980
|
-
async create(resource, body, idempotencyKey) {
|
|
6981
|
-
return transport.post(rp(resource), body, { idempotencyKey: idempotencyKey ?? newIdempotencyKey() });
|
|
6982
|
-
},
|
|
6983
|
-
async update(resource, id, patch, method = "PATCH") {
|
|
6984
|
-
const call = method === "PUT" ? transport.put : transport.patch;
|
|
6985
|
-
return call(ep(resource, id), patch);
|
|
6986
|
-
},
|
|
6987
|
-
async delete(resource, id) {
|
|
6988
|
-
try {
|
|
6989
|
-
await transport.del(ep(resource, id));
|
|
6990
|
-
} catch (error2) {
|
|
6991
|
-
if (error2 instanceof HasnaHttpError && error2.status === 404)
|
|
6992
|
-
return;
|
|
6993
|
-
throw error2;
|
|
6994
|
-
}
|
|
6995
|
-
}
|
|
6996
|
-
};
|
|
6997
|
-
}
|
|
6998
|
-
function resolveStorageClient(name, env = process.env, fetchImpl) {
|
|
6900
|
+
function resolveStoreClient(name, env = process.env) {
|
|
6999
6901
|
const resolution = resolveTransport(name, env);
|
|
7000
6902
|
if (resolution.misconfigured) {
|
|
6903
|
+
const wired2 = createClientTransport(name, env);
|
|
6904
|
+
if (wired2.transport === "http") {
|
|
6905
|
+
return {
|
|
6906
|
+
transport: "http",
|
|
6907
|
+
client: createHasnaStorageClient(name, wired2.client),
|
|
6908
|
+
resolution: {
|
|
6909
|
+
transport: "http",
|
|
6910
|
+
requested: "http",
|
|
6911
|
+
modeSource: resolution.modeSource === "default" ? "auto:api-url+seam-credential" : resolution.modeSource,
|
|
6912
|
+
baseUrl: wired2.resolution.baseUrl,
|
|
6913
|
+
apiKeyPresent: true,
|
|
6914
|
+
misconfigured: false,
|
|
6915
|
+
warning: null
|
|
6916
|
+
}
|
|
6917
|
+
};
|
|
6918
|
+
}
|
|
7001
6919
|
throw new Error(resolution.warning ?? `Client for '${name}' is misconfigured for the /v1 API.`);
|
|
7002
6920
|
}
|
|
7003
6921
|
if (resolution.transport === "sqlite" || !resolution.baseUrl) {
|
|
7004
6922
|
return { transport: "sqlite", client: null, resolution };
|
|
7005
6923
|
}
|
|
7006
|
-
const
|
|
7007
|
-
|
|
7008
|
-
if (!apiKey)
|
|
6924
|
+
const wired = createClientTransport(name, env);
|
|
6925
|
+
if (wired.transport !== "http") {
|
|
7009
6926
|
throw new Error(`Client for '${name}' resolved to the /v1 API without an API key.`);
|
|
7010
|
-
|
|
7011
|
-
return { transport: "http", client:
|
|
6927
|
+
}
|
|
6928
|
+
return { transport: "http", client: createHasnaStorageClient(name, wired.client), resolution };
|
|
7012
6929
|
}
|
|
7013
|
-
var
|
|
6930
|
+
var RETRY_STATUSES, IDEMPOTENT;
|
|
7014
6931
|
var init_client = __esm(() => {
|
|
7015
|
-
init_retired_deployment_modes();
|
|
7016
|
-
SERVER_BACKEND_VALUES = ["sqlite", "postgresql", "postgres"];
|
|
7017
|
-
HasnaHttpError = class HasnaHttpError extends Error {
|
|
7018
|
-
status;
|
|
7019
|
-
method;
|
|
7020
|
-
path;
|
|
7021
|
-
body;
|
|
7022
|
-
constructor(method, path, status, body) {
|
|
7023
|
-
super(`Hasna request failed: ${method} ${path} -> ${status}`);
|
|
7024
|
-
this.name = "HasnaHttpError";
|
|
7025
|
-
this.status = status;
|
|
7026
|
-
this.method = method;
|
|
7027
|
-
this.path = path;
|
|
7028
|
-
this.body = body;
|
|
7029
|
-
}
|
|
7030
|
-
};
|
|
7031
6932
|
RETRY_STATUSES = new Set([408, 425, 429, 500, 502, 503, 504]);
|
|
7032
6933
|
IDEMPOTENT = new Set(["GET", "HEAD", "PUT", "DELETE", "OPTIONS"]);
|
|
7033
6934
|
});
|
|
@@ -7059,6 +6960,22 @@ function unwrap(res, key) {
|
|
|
7059
6960
|
}
|
|
7060
6961
|
return res;
|
|
7061
6962
|
}
|
|
6963
|
+
async function listResource(client, resource, query) {
|
|
6964
|
+
const raw = await client.transport.get(`/${resource}`, query ? { query } : undefined);
|
|
6965
|
+
return { items: extractEnvelopeItems(raw, resource), raw };
|
|
6966
|
+
}
|
|
6967
|
+
function extractEnvelopeItems(raw, resource) {
|
|
6968
|
+
if (Array.isArray(raw))
|
|
6969
|
+
return raw;
|
|
6970
|
+
if (raw && typeof raw === "object") {
|
|
6971
|
+
const obj = raw;
|
|
6972
|
+
for (const key of [resource, "items", "data", "results", "rows", "records"]) {
|
|
6973
|
+
if (Array.isArray(obj[key]))
|
|
6974
|
+
return obj[key];
|
|
6975
|
+
}
|
|
6976
|
+
}
|
|
6977
|
+
return [];
|
|
6978
|
+
}
|
|
7062
6979
|
function apiStore(client) {
|
|
7063
6980
|
return {
|
|
7064
6981
|
mode: "http",
|
|
@@ -7066,7 +6983,7 @@ function apiStore(client) {
|
|
|
7066
6983
|
async createRecording(input, idempotencyKey) {
|
|
7067
6984
|
const keyCandidate = idempotencyKey === undefined && (input.id === undefined || input.id === null) ? randomUUID2() : idempotencyKey;
|
|
7068
6985
|
const identity = recordingCreateIdentity(input, keyCandidate, { bindIdempotencyKeyToId: false });
|
|
7069
|
-
const res = await client.create("recordings", identity.input, identity.idempotencyKey);
|
|
6986
|
+
const res = await client.create("recordings", identity.input, { idempotencyKey: identity.idempotencyKey });
|
|
7070
6987
|
return unwrap(res, "recording");
|
|
7071
6988
|
},
|
|
7072
6989
|
async getRecording(id) {
|
|
@@ -7074,7 +6991,7 @@ function apiStore(client) {
|
|
|
7074
6991
|
return res ? unwrap(res, "recording") : null;
|
|
7075
6992
|
},
|
|
7076
6993
|
async listRecordings(filter) {
|
|
7077
|
-
const { items } = await client
|
|
6994
|
+
const { items } = await listResource(client, "recordings", listQuery(filter));
|
|
7078
6995
|
return items;
|
|
7079
6996
|
},
|
|
7080
6997
|
async countRecordings(filter) {
|
|
@@ -7085,7 +7002,7 @@ function apiStore(client) {
|
|
|
7085
7002
|
const seenPageKeys = new Set;
|
|
7086
7003
|
while (pageRequests < maxPageRequests) {
|
|
7087
7004
|
pageRequests += 1;
|
|
7088
|
-
const { items, raw } = await client
|
|
7005
|
+
const { items, raw } = await listResource(client, "recordings", {
|
|
7089
7006
|
...listQuery(filter),
|
|
7090
7007
|
limit: pageLimit,
|
|
7091
7008
|
offset
|
|
@@ -7108,7 +7025,7 @@ function apiStore(client) {
|
|
|
7108
7025
|
throw new Error(`Recordings API exceeded ${maxPageRequests} pages while counting legacy results`);
|
|
7109
7026
|
},
|
|
7110
7027
|
async searchRecordings(query, filter) {
|
|
7111
|
-
const { items } = await client
|
|
7028
|
+
const { items } = await listResource(client, "recordings", listQuery({ ...filter ?? {}, search: query }));
|
|
7112
7029
|
return items;
|
|
7113
7030
|
},
|
|
7114
7031
|
async deleteRecording(id) {
|
|
@@ -7140,7 +7057,7 @@ function apiStore(client) {
|
|
|
7140
7057
|
return res ? unwrap(res, "agent") : null;
|
|
7141
7058
|
},
|
|
7142
7059
|
async listAgents() {
|
|
7143
|
-
const { items } = await client
|
|
7060
|
+
const { items } = await listResource(client, "agents");
|
|
7144
7061
|
return items;
|
|
7145
7062
|
},
|
|
7146
7063
|
async heartbeatAgent(idOrName) {
|
|
@@ -7180,7 +7097,7 @@ function apiStore(client) {
|
|
|
7180
7097
|
return res ? unwrap(res, "project") : null;
|
|
7181
7098
|
},
|
|
7182
7099
|
async listProjects() {
|
|
7183
|
-
const { items } = await client
|
|
7100
|
+
const { items } = await listResource(client, "projects");
|
|
7184
7101
|
return items;
|
|
7185
7102
|
},
|
|
7186
7103
|
async saveFeedback(input) {
|
|
@@ -7227,7 +7144,7 @@ async function countStoreRecordings(store, filter) {
|
|
|
7227
7144
|
function getStore(env = process.env) {
|
|
7228
7145
|
if (env === process.env && cached)
|
|
7229
7146
|
return cached;
|
|
7230
|
-
const resolved =
|
|
7147
|
+
const resolved = resolveStoreClient(APP, env);
|
|
7231
7148
|
const store = resolved.transport === "http" ? apiStore(resolved.client) : localStore;
|
|
7232
7149
|
if (env === process.env)
|
|
7233
7150
|
cached = store;
|
|
@@ -8229,6 +8146,7 @@ var init_mcp = __esm(async () => {
|
|
|
8229
8146
|
init_store();
|
|
8230
8147
|
init_transcriber();
|
|
8231
8148
|
init_enhancer();
|
|
8149
|
+
init_version();
|
|
8232
8150
|
init_machine();
|
|
8233
8151
|
config = loadConfig();
|
|
8234
8152
|
ensureDataDir(config);
|
|
@@ -8371,7 +8289,7 @@ async function startServer(port, options) {
|
|
|
8371
8289
|
}
|
|
8372
8290
|
var SECURITY_HEADERS, rateLimitMap, RATE_LIMIT_WINDOW_MS = 60000, RATE_LIMIT_MAX;
|
|
8373
8291
|
var init_serve = __esm(() => {
|
|
8374
|
-
|
|
8292
|
+
init_version();
|
|
8375
8293
|
init_v1();
|
|
8376
8294
|
init_openapi();
|
|
8377
8295
|
SECURITY_HEADERS = {
|
|
@@ -8385,6 +8303,7 @@ var init_serve = __esm(() => {
|
|
|
8385
8303
|
});
|
|
8386
8304
|
|
|
8387
8305
|
// src/server/index.ts
|
|
8306
|
+
init_version();
|
|
8388
8307
|
var DEFAULT_PORT = 8874;
|
|
8389
8308
|
function parsePort() {
|
|
8390
8309
|
const arg = process.argv.find((a) => a === "--port" || a.startsWith("--port="));
|
|
@@ -8421,8 +8340,7 @@ Commands:
|
|
|
8421
8340
|
migrate Apply the PostgreSQL schema, then exit. Idempotent.
|
|
8422
8341
|
|
|
8423
8342
|
Environment:
|
|
8424
|
-
|
|
8425
|
-
HASNA_RECORDINGS_DATABASE_URL PostgreSQL DSN (implies postgresql)
|
|
8343
|
+
HASNA_RECORDINGS_DATABASE_URL PostgreSQL DSN (present -> postgresql backend, else sqlite)
|
|
8426
8344
|
HASNA_RECORDINGS_API_SIGNING_KEY HMAC signing secret for API-key auth`);
|
|
8427
8345
|
}
|
|
8428
8346
|
async function runMigrate() {
|
|
@@ -8431,11 +8349,11 @@ async function runMigrate() {
|
|
|
8431
8349
|
getCloudPg: getCloudPg2,
|
|
8432
8350
|
migrateCloudSchema: migrateCloudSchema2,
|
|
8433
8351
|
pingCloudConnectivity: pingCloudConnectivity3,
|
|
8434
|
-
|
|
8352
|
+
resolveDatabaseUrl: resolveDatabaseUrl2
|
|
8435
8353
|
} = await Promise.resolve().then(() => (init_cloud(), exports_cloud));
|
|
8436
8354
|
const { assertCloudSchemaContract: assertCloudSchemaContract2 } = await Promise.resolve().then(() => (init_cloud_readiness(), exports_cloud_readiness));
|
|
8437
8355
|
const { runCloudMigration: runCloudMigration2 } = await Promise.resolve().then(() => (init_migrate_command(), exports_migrate_command));
|
|
8438
|
-
if (!
|
|
8356
|
+
if (!resolveDatabaseUrl2()) {
|
|
8439
8357
|
console.error("migrate: no database URL (HASNA_RECORDINGS_DATABASE_URL / RECORDINGS_DATABASE_URL / DATABASE_URL)");
|
|
8440
8358
|
process.exit(2);
|
|
8441
8359
|
}
|