@fonoster/callrecord 0.0.0-stage → 0.30.0
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/LICENSE +21 -0
- package/dist/CallRecordWriter.d.ts +135 -0
- package/dist/CallRecordWriter.js +545 -0
- package/dist/analytics.d.ts +39 -0
- package/dist/analytics.js +138 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +182 -0
- package/dist/clickhouse.d.ts +35 -0
- package/dist/clickhouse.js +176 -0
- package/dist/index.d.ts +31 -0
- package/dist/index.js +47 -0
- package/dist/indexEntry.d.ts +34 -0
- package/dist/indexEntry.js +68 -0
- package/dist/keys.d.ts +62 -0
- package/dist/keys.js +201 -0
- package/dist/objectStore.d.ts +59 -0
- package/dist/objectStore.js +247 -0
- package/dist/parts.d.ts +6 -0
- package/dist/parts.js +36 -0
- package/dist/recording.d.ts +72 -0
- package/dist/recording.js +378 -0
- package/dist/redact.d.ts +23 -0
- package/dist/redact.js +87 -0
- package/dist/sign.d.ts +47 -0
- package/dist/sign.js +136 -0
- package/dist/storage.d.ts +96 -0
- package/dist/storage.js +361 -0
- package/dist/types.d.ts +89 -0
- package/dist/types.js +2 -0
- package/dist/vcon.d.ts +38 -0
- package/dist/vcon.js +334 -0
- package/dist/verify.d.ts +32 -0
- package/dist/verify.js +47 -0
- package/package.json +42 -4
- package/schema/vcon-core-04.schema.json +1291 -0
- package/README.md +0 -3
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Fonoster Inc
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { RecordIndexEntry } from "./indexEntry";
|
|
2
|
+
import { KeyCustody } from "./keys";
|
|
3
|
+
import { SigningKey } from "./sign";
|
|
4
|
+
import { FsWorkingStore, RecordStore } from "./storage";
|
|
5
|
+
import { RecordEntry, SealingVersion } from "./types";
|
|
6
|
+
/** Call-record open question O1: a record is sealed within 30 s of hangup. */
|
|
7
|
+
export declare const SEAL_DEADLINE_MS = 30000;
|
|
8
|
+
/** Parts a retention policy or a deletion request can name (call-record "Retention"). */
|
|
9
|
+
export declare const RECORD_PARTS: readonly ["recording", "transcript", "messages"];
|
|
10
|
+
export type RecordPart = (typeof RECORD_PARTS)[number];
|
|
11
|
+
/** A maintenance request named another workspace than the stored record's (RV-B6). */
|
|
12
|
+
export declare class WorkspaceMismatchError extends Error {
|
|
13
|
+
constructor(callRef: string);
|
|
14
|
+
}
|
|
15
|
+
/** One audited deletion (call-record "every deletion ... produces an audit entry"). */
|
|
16
|
+
export type AuditEntry = {
|
|
17
|
+
callRef: string;
|
|
18
|
+
workspaceRef: string | null;
|
|
19
|
+
action: "delete_part" | "erase";
|
|
20
|
+
part: RecordPart | "all";
|
|
21
|
+
reason: string;
|
|
22
|
+
actor: string;
|
|
23
|
+
at: string;
|
|
24
|
+
/** The version that records the deletion. */
|
|
25
|
+
version: number;
|
|
26
|
+
};
|
|
27
|
+
export type CallRecordWriterOptions = {
|
|
28
|
+
working: FsWorkingStore;
|
|
29
|
+
/** The region's record store. */
|
|
30
|
+
store: RecordStore;
|
|
31
|
+
/**
|
|
32
|
+
* A workspace's own bucket, if it configured one (design V2). When it fails at seal the record
|
|
33
|
+
* stays in the region store and the index says so (open question O7, interim).
|
|
34
|
+
*/
|
|
35
|
+
workspaceStore?: (workspaceRef: string) => RecordStore | undefined;
|
|
36
|
+
/** A fixed key, or a custody that names the current key and signs (task 2.6). */
|
|
37
|
+
key: SigningKey | KeyCustody;
|
|
38
|
+
region: string;
|
|
39
|
+
/** Called after each sealed version: index it, send `call_record.sealed`. */
|
|
40
|
+
onSealed?: (entry: RecordIndexEntry) => void;
|
|
41
|
+
/**
|
|
42
|
+
* How often this writer marks its live calls' working records as alive (ST-5), so a writer
|
|
43
|
+
* sweeping the same directory leaves them alone. Well under the sweep's deadline.
|
|
44
|
+
*/
|
|
45
|
+
heartbeatMs?: number;
|
|
46
|
+
};
|
|
47
|
+
/**
|
|
48
|
+
* Builds call records live and seals them at hangup (call-record "The record is built during the
|
|
49
|
+
* call and sealed at hangup"). It implements the gateway's CallRecordSink interface.
|
|
50
|
+
*/
|
|
51
|
+
export declare class CallRecordWriter {
|
|
52
|
+
private readonly options;
|
|
53
|
+
/** Calls appended in this process and not closed yet; the sweep leaves them alone. */
|
|
54
|
+
private readonly active;
|
|
55
|
+
private readonly sealing;
|
|
56
|
+
private readonly custody;
|
|
57
|
+
/** Names this writer in seal locks on a shared working directory. */
|
|
58
|
+
private readonly owner;
|
|
59
|
+
private heartbeat?;
|
|
60
|
+
constructor(options: CallRecordWriterOptions);
|
|
61
|
+
get region(): string;
|
|
62
|
+
append(callRef: string, entry: RecordEntry): void;
|
|
63
|
+
/** Marks every live call of this writer as alive (see `heartbeatMs`). */
|
|
64
|
+
beat(): void;
|
|
65
|
+
/** Stops the heartbeat (shutdown; a writer that dies stops it too). */
|
|
66
|
+
stop(): void;
|
|
67
|
+
/** Where the recorder writes this call's tracks (removed once the record is sealed). */
|
|
68
|
+
recordingDir(callRef: string): string;
|
|
69
|
+
/** The call ended: seal its record in the background. */
|
|
70
|
+
close(callRef: string): void;
|
|
71
|
+
/** Resolves once every seal in progress has finished (tests, shutdown). */
|
|
72
|
+
flush(): Promise<void>;
|
|
73
|
+
/** The store a workspace's records go to. */
|
|
74
|
+
storeFor(workspaceRef?: string | null): RecordStore;
|
|
75
|
+
/**
|
|
76
|
+
* The store that holds an existing record. With its indexed location (RV-B10) that is the
|
|
77
|
+
* store at that location: a record whose workspace bucket failed at seal stays in the region
|
|
78
|
+
* store, and a workspace that configured a bucket later keeps its older records where they
|
|
79
|
+
* are. Without a location, the workspace's current store.
|
|
80
|
+
*/
|
|
81
|
+
storeAt(location: string | undefined, workspaceRef?: string | null): RecordStore;
|
|
82
|
+
/** Seals a working record as version 1 and returns it; idempotent while in progress. */
|
|
83
|
+
seal(callRef: string): Promise<SealingVersion>;
|
|
84
|
+
/** The sealed version 1 another writer stored, once its seal lock is gone. */
|
|
85
|
+
private sealedByOther;
|
|
86
|
+
/**
|
|
87
|
+
* Seals under a lock in the working directory, so of all the writers that share it exactly one
|
|
88
|
+
* seals a call (its hangup on the owner, or a sweep elsewhere), once (ST-5).
|
|
89
|
+
*/
|
|
90
|
+
private doSeal;
|
|
91
|
+
private sealLocked;
|
|
92
|
+
private sealed;
|
|
93
|
+
/**
|
|
94
|
+
* Seals records whose calls stopped appending more than `deadlineMs` ago without a hangup (a
|
|
95
|
+
* gateway that crashed). Returns the callRefs sealed.
|
|
96
|
+
*/
|
|
97
|
+
sweep(now?: number, deadlineMs?: number): Promise<string[]>;
|
|
98
|
+
/** Adds a version derived from the current one (it references its predecessor). */
|
|
99
|
+
private newVersion;
|
|
100
|
+
/**
|
|
101
|
+
* Adds to a sealed record as a new version that references its predecessor (call-record
|
|
102
|
+
* "Additions after sealing create new versions"); the previous version is unchanged.
|
|
103
|
+
*/
|
|
104
|
+
addVersion(callRef: string, additions: {
|
|
105
|
+
analysis?: Record<string, unknown>[];
|
|
106
|
+
}, workspaceRef?: string, location?: string): Promise<SealingVersion>;
|
|
107
|
+
/**
|
|
108
|
+
* Deletes parts of a record (retention policy or a request) and writes a version that records
|
|
109
|
+
* each removal (call-record "Retention follows workspace policy and deletions are audited").
|
|
110
|
+
* The recording and the messages are files; the transcript lives inside the vCons, so earlier
|
|
111
|
+
* versions' contents are deleted too and only their manifests remain.
|
|
112
|
+
*/
|
|
113
|
+
deleteParts(callRef: string, requested: RecordPart[], by: {
|
|
114
|
+
reason: string;
|
|
115
|
+
actor: string;
|
|
116
|
+
workspaceRef?: string | null;
|
|
117
|
+
location?: string;
|
|
118
|
+
}): Promise<{
|
|
119
|
+
sealed: SealingVersion;
|
|
120
|
+
audit: AuditEntry[];
|
|
121
|
+
}>;
|
|
122
|
+
/**
|
|
123
|
+
* Erases one call (call-record "Erasing one call"): every file and version is deleted, and a
|
|
124
|
+
* signed tombstone version states when, why and by whom. It holds no call content.
|
|
125
|
+
*/
|
|
126
|
+
erase(callRef: string, by: {
|
|
127
|
+
reason: string;
|
|
128
|
+
actor: string;
|
|
129
|
+
workspaceRef?: string | null;
|
|
130
|
+
location?: string;
|
|
131
|
+
}): Promise<{
|
|
132
|
+
audit: AuditEntry[];
|
|
133
|
+
version: number;
|
|
134
|
+
}>;
|
|
135
|
+
}
|