@harperfast/harper 5.3.0-beta.1 → 5.3.0-beta.2
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/components/DESIGN.md +421 -0
- package/components/mcp/DESIGN.md +109 -0
- package/components/mcp/audit.ts +21 -17
- package/config/DESIGN.md +306 -0
- package/dataLayer/DESIGN.md +179 -0
- package/dataLayer/restoreMarker.ts +92 -25
- package/dist/components/mcp/audit.d.ts +2 -1
- package/dist/components/mcp/audit.js +21 -17
- package/dist/components/mcp/audit.js.map +1 -1
- package/dist/dataLayer/restoreMarker.d.ts +21 -8
- package/dist/dataLayer/restoreMarker.js +94 -27
- package/dist/dataLayer/restoreMarker.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +6 -1
- package/dist/index.js.map +1 -1
- package/dist/resources/RecordEncoder.js +25 -5
- package/dist/resources/RecordEncoder.js.map +1 -1
- package/dist/resources/Table.js +48 -2
- package/dist/resources/Table.js.map +1 -1
- package/dist/resources/analytics/write.d.ts +3 -0
- package/dist/resources/analytics/write.js +39 -13
- package/dist/resources/analytics/write.js.map +1 -1
- package/dist/resources/crdt.d.ts +10 -0
- package/dist/resources/crdt.js +22 -0
- package/dist/resources/crdt.js.map +1 -1
- package/dist/resources/databases.js +1 -1
- package/dist/resources/databases.js.map +1 -1
- package/dist/resources/indexes/HierarchicalNavigableSmallWorld.d.ts +2 -2
- package/dist/resources/indexes/HierarchicalNavigableSmallWorld.js +43 -24
- package/dist/resources/indexes/HierarchicalNavigableSmallWorld.js.map +1 -1
- package/dist/resources/indexes/fullTextDerivedIndex.d.ts +81 -0
- package/dist/resources/indexes/fullTextDerivedIndex.js +1004 -0
- package/dist/resources/indexes/fullTextDerivedIndex.js.map +1 -0
- package/dist/resources/indexes/fullTextNativeBinding.d.ts +78 -0
- package/dist/resources/indexes/fullTextNativeBinding.js +85 -0
- package/dist/resources/indexes/fullTextNativeBinding.js.map +1 -0
- package/dist/resources/indexes/nativeFullTextDerivedIndexLifecycle.d.ts +24 -0
- package/dist/resources/indexes/nativeFullTextDerivedIndexLifecycle.js +149 -0
- package/dist/resources/indexes/nativeFullTextDerivedIndexLifecycle.js.map +1 -0
- package/dist/resources/recordLockCoordinator.d.ts +5 -5
- package/dist/resources/recordLockCoordinator.js +48 -16
- package/dist/resources/recordLockCoordinator.js.map +1 -1
- package/dist/resources/transactionBroadcast.js +4 -6
- package/dist/resources/transactionBroadcast.js.map +1 -1
- package/dist/security/auth.js +59 -23
- package/dist/security/auth.js.map +1 -1
- package/dist/security/deferredAuthentication.d.ts +11 -0
- package/dist/security/deferredAuthentication.js +25 -3
- package/dist/security/deferredAuthentication.js.map +1 -1
- package/dist/security/jsLoader.js +3 -0
- package/dist/security/jsLoader.js.map +1 -1
- package/dist/server/REST.js +6 -3
- package/dist/server/REST.js.map +1 -1
- package/dist/server/mqtt.js +5 -1
- package/dist/server/mqtt.js.map +1 -1
- package/dist/server/serverHelpers/serverUtilities.d.ts +3 -3
- package/dist/server/serverHelpers/serverUtilities.js +14 -3
- package/dist/server/serverHelpers/serverUtilities.js.map +1 -1
- package/dist/server/serverHelpers/uwsServer.js +4 -1
- package/dist/server/serverHelpers/uwsServer.js.map +1 -1
- package/dist/server/serverHelpers/webSocketCloseReason.d.ts +2 -0
- package/dist/server/serverHelpers/webSocketCloseReason.js +29 -0
- package/dist/server/serverHelpers/webSocketCloseReason.js.map +1 -0
- package/dist/utility/logging/harper_logger.js +1 -0
- package/dist/utility/logging/harper_logger.js.map +1 -1
- package/index.ts +3 -0
- package/npm-shrinkwrap.json +104 -104
- package/package.json +6 -5
- package/resources/DESIGN.md +568 -3
- package/resources/RecordEncoder.ts +27 -5
- package/resources/Table.ts +49 -3
- package/resources/analytics/DESIGN.md +38 -0
- package/resources/analytics/write.ts +40 -14
- package/resources/crdt.ts +22 -0
- package/resources/databases.ts +1 -1
- package/resources/indexes/DESIGN.md +833 -0
- package/resources/indexes/HierarchicalNavigableSmallWorld.ts +44 -25
- package/resources/indexes/fullTextDerivedIndex.ts +1165 -0
- package/resources/indexes/fullTextNativeBinding.ts +146 -0
- package/resources/indexes/nativeFullTextDerivedIndexLifecycle.ts +181 -0
- package/resources/record-locks.md +1407 -0
- package/resources/recordLockCoordinator.ts +61 -22
- package/resources/scheduler/DESIGN.md +40 -0
- package/resources/transactionBroadcast.ts +4 -4
- package/security/DESIGN.md +175 -0
- package/security/auth.ts +53 -24
- package/security/deferredAuthentication.ts +24 -2
- package/security/jsLoader.ts +3 -0
- package/server/DESIGN.md +264 -0
- package/server/REST.ts +6 -3
- package/server/mqtt.ts +6 -4
- package/server/serverHelpers/serverUtilities.ts +14 -3
- package/server/serverHelpers/uwsServer.ts +4 -1
- package/server/serverHelpers/webSocketCloseReason.ts +25 -0
- package/studio/web/assets/{Chat-D3j-1yY1.js → Chat-DADFFGe_.js} +1 -1
- package/studio/web/assets/{FloatingChat-BxJGYcfB.js → FloatingChat-D_mI-rZ7.js} +3 -3
- package/studio/web/assets/{apiToken-CT55oWOe.js → apiToken-c2NiSDHa.js} +1 -1
- package/studio/web/assets/{applications-D9Ct9_vm.js → applications-DktUqh7G.js} +1 -1
- package/studio/web/assets/{cssMode-DV8H7VwA.js → cssMode-Cs_75Xhw.js} +1 -1
- package/studio/web/assets/{editor-uatc0unt.js → editor-19b-Y1IN.js} +1 -1
- package/studio/web/assets/{html-Bm6D6paN.js → html-DiYEQMpB.js} +1 -1
- package/studio/web/assets/{htmlMode-CEn7tpLG.js → htmlMode-CmR0y7P_.js} +1 -1
- package/studio/web/assets/{index-BIXW6Pu4.js → index-Dm0rfkJ7.js} +5 -5
- package/studio/web/assets/{index.lazy-UI7L-Vrk.js → index.lazy-7vqt2CC3.js} +1 -1
- package/studio/web/assets/{javascript-CJ0G3AFZ.js → javascript-BWtCFuOt.js} +1 -1
- package/studio/web/assets/{jsonMode-DQADAYEa.js → jsonMode-Buzzbv9y.js} +1 -1
- package/studio/web/assets/{languageServices-CAQJXWcI.js → languageServices-SqsFWfTM.js} +1 -1
- package/studio/web/assets/{lspLanguageFeatures-CCQ8P5sY.js → lspLanguageFeatures-EMV5cmjo.js} +1 -1
- package/studio/web/assets/{notifications-Cvb3P1lB.js → notifications-CAB-LZWT.js} +1 -1
- package/studio/web/assets/{notifications-BbxTU6Aw.js → notifications-DRzmSRxM.js} +1 -1
- package/studio/web/assets/{profile-Yyb7gsvL.js → profile-BNKAl79n.js} +1 -1
- package/studio/web/assets/{regions-OgjGHlU5.js → regions-CUow_Zw2.js} +1 -1
- package/studio/web/assets/{register-6qwNEOY3.js → register-Dkt3WUMp.js} +2 -2
- package/studio/web/assets/{setComponentFile-BilDMtgB.js → setComponentFile-BZRfMD0N.js} +1 -1
- package/studio/web/assets/{setup-J6qJ7OIU.js → setup-D_yiEPO2.js} +2 -2
- package/studio/web/assets/{status-0RWGcfyD.js → status-DhHh1Ge-.js} +1 -1
- package/studio/web/assets/{toggleHighContrast-BIn-vErT.js → toggleHighContrast-D7L1PDtV.js} +1 -1
- package/studio/web/assets/{tsMode-DgUXku4d.js → tsMode-CCwLk1YS.js} +1 -1
- package/studio/web/assets/{typescript-C9orXcsM.js → typescript-BP1j1mjn.js} +1 -1
- package/studio/web/assets/{useEntityRestURL-BEoXXbUB.js → useEntityRestURL-D7bnYxLw.js} +1 -1
- package/studio/web/assets/{workers-JVzSDmgx.js → workers-tOuCNT17.js} +1 -1
- package/studio/web/assets/{xml-Cq-S8S4X.js → xml-BSG_3mQT.js} +1 -1
- package/studio/web/assets/{yaml-sfoRdh1M.js → yaml-DxiLprBB.js} +1 -1
- package/studio/web/index.html +1 -1
- package/utility/DESIGN.md +55 -0
- package/utility/logging/harper_logger.ts +1 -0
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
openSync,
|
|
9
9
|
readdirSync,
|
|
10
10
|
readFileSync,
|
|
11
|
+
renameSync,
|
|
11
12
|
unlinkSync,
|
|
12
13
|
writeSync,
|
|
13
14
|
} from 'node:fs';
|
|
@@ -39,11 +40,17 @@ import { tryFileLock, fileLockRelease } from '@harperfast/rocksdb-js';
|
|
|
39
40
|
* duration of a restore, and briefly by `dropDatabase` so the two serialize on the same primitive.
|
|
40
41
|
* Known limitation: the lock is owned by the process, so if the restore job's worker *thread*
|
|
41
42
|
* dies without the process exiting, the lock stays held (restores 409) until Harper restarts.
|
|
42
|
-
* - `<meta-dir>/<key>.restoring` — the completion marker.
|
|
43
|
-
* acquired and before the destructive restore begins; deleted only after
|
|
44
|
-
* successfully, while still holding the lock. Its *existence* means "a
|
|
45
|
-
* not finished successfully". Its first line records the database
|
|
46
|
-
*
|
|
43
|
+
* - `<meta-dir>/<key>.restoring` — the completion marker. Published (temp → fsync → rename → parent
|
|
44
|
+
* fsync) after the lock is acquired and before the destructive restore begins; deleted only after
|
|
45
|
+
* the restore completes successfully, while still holding the lock. Its *existence* means "a
|
|
46
|
+
* restore started and has not finished successfully". Its first line records the database
|
|
47
|
+
* directory name as a fallback so the startup scan can map a marker whose database directory is
|
|
48
|
+
* missing without decoding the hashed key.
|
|
49
|
+
*
|
|
50
|
+
* The rename is what makes the marker trustworthy: the marker path only ever holds the previous
|
|
51
|
+
* content or the complete new content, so a torn write can never replace a valid marker with one
|
|
52
|
+
* the scan reads as empty (and therefore honors as no block). An intact marker is also never
|
|
53
|
+
* rewritten at all — see `beginRestore`.
|
|
47
54
|
*/
|
|
48
55
|
|
|
49
56
|
// The backtick makes this an illegal database name (schemaRegex rejects `/` and backtick only), so
|
|
@@ -51,6 +58,9 @@ import { tryFileLock, fileLockRelease } from '@harperfast/rocksdb-js';
|
|
|
51
58
|
export const RESTORE_META_DIR = '`restore`';
|
|
52
59
|
export const RESTORE_LOCK_SUFFIX = '.lock';
|
|
53
60
|
export const RESTORING_MARKER_SUFFIX = '.restoring';
|
|
61
|
+
// Deliberately not a `.restoring` suffix: `scanBlockedRestores` selects markers by that suffix, and
|
|
62
|
+
// a half-written temp must never be mistaken for one.
|
|
63
|
+
const MARKER_TEMP_SUFFIX = '.tmp';
|
|
54
64
|
|
|
55
65
|
/**
|
|
56
66
|
* Directory holding the restore metadata for a database — the reserved `` `restore` `` sibling of
|
|
@@ -180,17 +190,29 @@ export function releaseRestoreLock(lock: RestoreLock): void {
|
|
|
180
190
|
}
|
|
181
191
|
|
|
182
192
|
/**
|
|
183
|
-
*
|
|
184
|
-
*
|
|
185
|
-
* a
|
|
186
|
-
*
|
|
193
|
+
* Whether a marker on disk still blocks the database it belongs to. `scanBlockedRestores` maps a
|
|
194
|
+
* marker to a database by its first line, so the line has to be the whole name: a torn write that
|
|
195
|
+
* left a prefix of it ("ord" for "orders") is non-empty and reads as valid, but blocks a database
|
|
196
|
+
* that does not exist while the real one loads.
|
|
187
197
|
*/
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
198
|
+
function markerIsIntact(markerPath: string, dbPath: string): boolean {
|
|
199
|
+
try {
|
|
200
|
+
return readFileSync(markerPath, 'utf8').split('\n', 1)[0] === basename(dbPath);
|
|
201
|
+
} catch {
|
|
202
|
+
return false;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Publish the restoring marker atomically. The caller must already hold the restore lock, which is
|
|
208
|
+
* what makes the fixed temp name safe: only one writer per database can exist at a time, so a temp
|
|
209
|
+
* left by an earlier crash is this database's own debris and is simply overwritten.
|
|
210
|
+
*/
|
|
211
|
+
function publishRestoringMarker(dbPath: string): void {
|
|
212
|
+
const metaDir = restoreMetaDir(dbPath);
|
|
213
|
+
const tempPath = join(metaDir, restoreMetaKey(dbPath) + MARKER_TEMP_SUFFIX);
|
|
192
214
|
try {
|
|
193
|
-
const fd = openSync(
|
|
215
|
+
const fd = openSync(tempPath, 'w');
|
|
194
216
|
try {
|
|
195
217
|
// first line is the database directory name so the startup scan can map this marker back to
|
|
196
218
|
// the database it blocks without reversing the hashed key
|
|
@@ -199,9 +221,44 @@ export function beginRestore(dbPath: string): RestoreLock {
|
|
|
199
221
|
} finally {
|
|
200
222
|
closeSync(fd);
|
|
201
223
|
}
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
224
|
+
renameSync(tempPath, restoringMarkerPath(dbPath));
|
|
225
|
+
} catch (error) {
|
|
226
|
+
try {
|
|
227
|
+
unlinkSync(tempPath);
|
|
228
|
+
} catch {
|
|
229
|
+
// debris either way; the write failure is the error worth reporting
|
|
230
|
+
}
|
|
231
|
+
throw error;
|
|
232
|
+
}
|
|
233
|
+
// fsync the metadata directory so the marker's directory entry is durable — without this a
|
|
234
|
+
// power loss can lose the entry, and a half-purged database would load as healthy
|
|
235
|
+
fsyncDir(metaDir);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Acquire the per-database restore lock and ensure the restoring marker is in place. Call before any
|
|
240
|
+
* destructive step. Returns the lock (with `preexisting` set when a marker was already present, so
|
|
241
|
+
* a failed recovery attempt knows not to clear it). Throws (statusCode 409) if another restore
|
|
242
|
+
* already holds the lock.
|
|
243
|
+
*
|
|
244
|
+
* An intact marker is left exactly as it is. A recovery attempt runs over a directory an earlier
|
|
245
|
+
* restore may have half-purged, so the marker it finds is the only thing keeping that directory
|
|
246
|
+
* from loading as healthy; rewriting it buys nothing (the content it would write is the content
|
|
247
|
+
* already there) and risks everything.
|
|
248
|
+
*/
|
|
249
|
+
export function beginRestore(dbPath: string): RestoreLock {
|
|
250
|
+
const markerPath = restoringMarkerPath(dbPath);
|
|
251
|
+
const lock = acquireRestoreLock(dbPath);
|
|
252
|
+
// Sampled while holding the lock, not before it: a restore that waited out an earlier one would
|
|
253
|
+
// otherwise carry the earlier run's "no marker" reading, and on its own pre-destruction failure
|
|
254
|
+
// clear the marker protecting a directory that run had already half-purged.
|
|
255
|
+
const preexisting = existsSync(markerPath);
|
|
256
|
+
try {
|
|
257
|
+
if (!preexisting || !markerIsIntact(markerPath, dbPath)) publishRestoringMarker(dbPath);
|
|
258
|
+
// An intact marker is kept, but its durability is not assumed: the publisher that wrote it may
|
|
259
|
+
// have been interrupted between the rename and this flush, which would leave the directory
|
|
260
|
+
// entry — the thing the startup scan reads — still only in the page cache.
|
|
261
|
+
else fsyncDir(restoreMetaDir(dbPath));
|
|
205
262
|
} catch (error) {
|
|
206
263
|
fileLockRelease(lock.token);
|
|
207
264
|
throw error;
|
|
@@ -251,24 +308,34 @@ export function clearRestoreMarker(lock: RestoreLock): void {
|
|
|
251
308
|
}
|
|
252
309
|
|
|
253
310
|
/**
|
|
254
|
-
* Scan a databases root's reserved `` `restore` `` metadata directory and report every database
|
|
255
|
-
*
|
|
311
|
+
* Scan a databases root's reserved `` `restore` `` metadata directory and report every database
|
|
312
|
+
* currently blocked from loading. Existing database entries are mapped to markers by their hashed
|
|
313
|
+
* keys, so corrupt marker contents cannot unblock them; the first line remains the fallback for a
|
|
314
|
+
* marker whose database directory is missing.
|
|
256
315
|
* Returns `[dbName, state]` pairs for markers whose state is `in-progress` or `incomplete`
|
|
257
316
|
* (a `clear` result means the marker was removed concurrently and the database is loadable).
|
|
258
317
|
*/
|
|
259
318
|
export function scanBlockedRestores(databasesRoot: string): Array<[string, RestoreState]> {
|
|
260
319
|
const metaDir = join(databasesRoot, RESTORE_META_DIR);
|
|
261
320
|
if (!existsSync(metaDir)) return [];
|
|
321
|
+
const databaseNamesByMarker = new Map(
|
|
322
|
+
readdirSync(databasesRoot, { withFileTypes: true })
|
|
323
|
+
.filter((entry) => entry.name !== RESTORE_META_DIR)
|
|
324
|
+
.map((entry) => [restoreMetaKey(join(databasesRoot, entry.name)) + RESTORING_MARKER_SUFFIX, entry.name])
|
|
325
|
+
);
|
|
262
326
|
const blocked: Array<[string, RestoreState]> = [];
|
|
263
327
|
for (const entry of readdirSync(metaDir, { withFileTypes: true })) {
|
|
264
328
|
if (!entry.isFile() || !entry.name.endsWith(RESTORING_MARKER_SUFFIX)) continue;
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
329
|
+
const markerPath = join(metaDir, entry.name);
|
|
330
|
+
let dbName = databaseNamesByMarker.get(entry.name);
|
|
331
|
+
if (!dbName) {
|
|
332
|
+
try {
|
|
333
|
+
dbName = readFileSync(markerPath, 'utf8').split('\n', 1)[0];
|
|
334
|
+
} catch {
|
|
335
|
+
continue; // marker removed concurrently
|
|
336
|
+
}
|
|
337
|
+
if (!dbName || restoringMarkerPath(join(databasesRoot, dbName)) !== markerPath) continue;
|
|
270
338
|
}
|
|
271
|
-
if (!dbName) continue;
|
|
272
339
|
const state = checkRestoreState(join(databasesRoot, dbName));
|
|
273
340
|
if (state !== 'clear') blocked.push([dbName, state]);
|
|
274
341
|
}
|
|
@@ -16,7 +16,8 @@ export interface AuditEntry {
|
|
|
16
16
|
* a credential buried below the depth limit cannot leak. Returns a shallow
|
|
17
17
|
* clone — the caller's payload is never mutated.
|
|
18
18
|
*/
|
|
19
|
-
export declare function redactArgs(value: unknown, depth?: number,
|
|
19
|
+
export declare function redactArgs(value: unknown, depth?: number, redactionFields?: ReadonlySet<string>): unknown;
|
|
20
|
+
export declare function redactArgsForTool(value: unknown, tool: string): unknown;
|
|
20
21
|
/** Mask a session id for logging — first 8 chars, suffix elided. */
|
|
21
22
|
export declare function maskSessionId(id: string): string;
|
|
22
23
|
/**
|
|
@@ -4,6 +4,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.redactArgs = redactArgs;
|
|
7
|
+
exports.redactArgsForTool = redactArgsForTool;
|
|
7
8
|
exports.maskSessionId = maskSessionId;
|
|
8
9
|
exports.emitAuditEntry = emitAuditEntry;
|
|
9
10
|
/**
|
|
@@ -14,23 +15,23 @@ exports.emitAuditEntry = emitAuditEntry;
|
|
|
14
15
|
* (session id, profile, tool name).
|
|
15
16
|
*
|
|
16
17
|
* Argument summarization runs through a redaction step that drops anything
|
|
17
|
-
* that looks like a credential (
|
|
18
|
+
* that looks like a credential (secret/password/token). Operators who need
|
|
18
19
|
* stricter PII handling configure `mcp.audit.argumentRedactor` to a custom
|
|
19
20
|
* function via a future component-author hook (v1.1).
|
|
20
21
|
*/
|
|
21
22
|
const harper_logger_ts_1 = __importDefault(require("../../utility/logging/harper_logger.js"));
|
|
22
23
|
const REDACTION_PATTERN = /(secret|password|token|api[-_]?key|credentials?|auth)/i;
|
|
23
|
-
//
|
|
24
|
-
//
|
|
25
|
-
//
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
24
|
+
// Both secret tools carry all three fields, not just the ones each declares: MCP forwards arguments
|
|
25
|
+
// as-is and audits them after the handler, so a field the tool rejects is still logged. Mirrors what
|
|
26
|
+
// the REST operations log strips unconditionally (UNLOGGABLE_OPERATION_FIELDS).
|
|
27
|
+
const SECRET_VALUE_FIELDS = new Set(['value', 'values', 'envelope']);
|
|
28
|
+
// Per tool, not global: `value`/`values` are ordinary params on many other operations.
|
|
29
|
+
const REDACTION_FIELDS_BY_TOOL = new Map([
|
|
30
|
+
['set_secret', SECRET_VALUE_FIELDS],
|
|
31
|
+
['set_env_value', SECRET_VALUE_FIELDS],
|
|
32
|
+
['add_ssh_key', new Set(['key'])],
|
|
33
|
+
['update_ssh_key', new Set(['key'])],
|
|
34
|
+
]);
|
|
34
35
|
const REDACTION_PLACEHOLDER = '[redacted]';
|
|
35
36
|
const MAX_REDACTION_DEPTH = 10;
|
|
36
37
|
/**
|
|
@@ -40,25 +41,28 @@ const MAX_REDACTION_DEPTH = 10;
|
|
|
40
41
|
* a credential buried below the depth limit cannot leak. Returns a shallow
|
|
41
42
|
* clone — the caller's payload is never mutated.
|
|
42
43
|
*/
|
|
43
|
-
function redactArgs(value, depth = 0,
|
|
44
|
+
function redactArgs(value, depth = 0, redactionFields) {
|
|
44
45
|
if (value === null || typeof value !== 'object')
|
|
45
46
|
return value;
|
|
46
47
|
if (depth > MAX_REDACTION_DEPTH)
|
|
47
48
|
return REDACTION_PLACEHOLDER;
|
|
48
49
|
if (Array.isArray(value)) {
|
|
49
|
-
return value.map((v) => redactArgs(v, depth + 1,
|
|
50
|
+
return value.map((v) => redactArgs(v, depth + 1, redactionFields));
|
|
50
51
|
}
|
|
51
52
|
const out = {};
|
|
52
53
|
for (const [k, v] of Object.entries(value)) {
|
|
53
|
-
if (REDACTION_PATTERN.test(k) || (
|
|
54
|
+
if (REDACTION_PATTERN.test(k) || redactionFields?.has(k.toLowerCase())) {
|
|
54
55
|
out[k] = REDACTION_PLACEHOLDER;
|
|
55
56
|
}
|
|
56
57
|
else {
|
|
57
|
-
out[k] = redactArgs(v, depth + 1,
|
|
58
|
+
out[k] = redactArgs(v, depth + 1, redactionFields);
|
|
58
59
|
}
|
|
59
60
|
}
|
|
60
61
|
return out;
|
|
61
62
|
}
|
|
63
|
+
function redactArgsForTool(value, tool) {
|
|
64
|
+
return redactArgs(value, 0, REDACTION_FIELDS_BY_TOOL.get(tool));
|
|
65
|
+
}
|
|
62
66
|
/** Mask a session id for logging — first 8 chars, suffix elided. */
|
|
63
67
|
function maskSessionId(id) {
|
|
64
68
|
if (typeof id !== 'string' || id.length <= 8)
|
|
@@ -75,7 +79,7 @@ function emitAuditEntry(entry) {
|
|
|
75
79
|
const masked = {
|
|
76
80
|
...entry,
|
|
77
81
|
sessionId: maskSessionId(entry.sessionId),
|
|
78
|
-
args:
|
|
82
|
+
args: redactArgsForTool(entry.args, entry.tool),
|
|
79
83
|
};
|
|
80
84
|
harper_logger_ts_1.default.info({ category: 'mcp.audit', ...masked });
|
|
81
85
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"audit.js","sourceRoot":"","sources":["../../../components/mcp/audit.ts"],"names":[],"mappings":";;;;;AAgDA,gCAeC;AAGD,sCAGC;AAOD,wCAaC;
|
|
1
|
+
{"version":3,"file":"audit.js","sourceRoot":"","sources":["../../../components/mcp/audit.ts"],"names":[],"mappings":"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"}
|
|
@@ -22,11 +22,17 @@
|
|
|
22
22
|
* duration of a restore, and briefly by `dropDatabase` so the two serialize on the same primitive.
|
|
23
23
|
* Known limitation: the lock is owned by the process, so if the restore job's worker *thread*
|
|
24
24
|
* dies without the process exiting, the lock stays held (restores 409) until Harper restarts.
|
|
25
|
-
* - `<meta-dir>/<key>.restoring` — the completion marker.
|
|
26
|
-
* acquired and before the destructive restore begins; deleted only after
|
|
27
|
-
* successfully, while still holding the lock. Its *existence* means "a
|
|
28
|
-
* not finished successfully". Its first line records the database
|
|
29
|
-
*
|
|
25
|
+
* - `<meta-dir>/<key>.restoring` — the completion marker. Published (temp → fsync → rename → parent
|
|
26
|
+
* fsync) after the lock is acquired and before the destructive restore begins; deleted only after
|
|
27
|
+
* the restore completes successfully, while still holding the lock. Its *existence* means "a
|
|
28
|
+
* restore started and has not finished successfully". Its first line records the database
|
|
29
|
+
* directory name as a fallback so the startup scan can map a marker whose database directory is
|
|
30
|
+
* missing without decoding the hashed key.
|
|
31
|
+
*
|
|
32
|
+
* The rename is what makes the marker trustworthy: the marker path only ever holds the previous
|
|
33
|
+
* content or the complete new content, so a torn write can never replace a valid marker with one
|
|
34
|
+
* the scan reads as empty (and therefore honors as no block). An intact marker is also never
|
|
35
|
+
* rewritten at all — see `beginRestore`.
|
|
30
36
|
*/
|
|
31
37
|
export declare const RESTORE_META_DIR = "`restore`";
|
|
32
38
|
export declare const RESTORE_LOCK_SUFFIX = ".lock";
|
|
@@ -91,10 +97,15 @@ export declare function acquireRestoreLock(dbPath: string): RestoreLock;
|
|
|
91
97
|
*/
|
|
92
98
|
export declare function releaseRestoreLock(lock: RestoreLock): void;
|
|
93
99
|
/**
|
|
94
|
-
* Acquire the per-database restore lock and
|
|
100
|
+
* Acquire the per-database restore lock and ensure the restoring marker is in place. Call before any
|
|
95
101
|
* destructive step. Returns the lock (with `preexisting` set when a marker was already present, so
|
|
96
102
|
* a failed recovery attempt knows not to clear it). Throws (statusCode 409) if another restore
|
|
97
103
|
* already holds the lock.
|
|
104
|
+
*
|
|
105
|
+
* An intact marker is left exactly as it is. A recovery attempt runs over a directory an earlier
|
|
106
|
+
* restore may have half-purged, so the marker it finds is the only thing keeping that directory
|
|
107
|
+
* from loading as healthy; rewriting it buys nothing (the content it would write is the content
|
|
108
|
+
* already there) and risks everything.
|
|
98
109
|
*/
|
|
99
110
|
export declare function beginRestore(dbPath: string): RestoreLock;
|
|
100
111
|
/**
|
|
@@ -114,8 +125,10 @@ export declare function abandonRestore(lock: RestoreLock): void;
|
|
|
114
125
|
*/
|
|
115
126
|
export declare function clearRestoreMarker(lock: RestoreLock): void;
|
|
116
127
|
/**
|
|
117
|
-
* Scan a databases root's reserved `` `restore` `` metadata directory and report every database
|
|
118
|
-
*
|
|
128
|
+
* Scan a databases root's reserved `` `restore` `` metadata directory and report every database
|
|
129
|
+
* currently blocked from loading. Existing database entries are mapped to markers by their hashed
|
|
130
|
+
* keys, so corrupt marker contents cannot unblock them; the first line remains the fallback for a
|
|
131
|
+
* marker whose database directory is missing.
|
|
119
132
|
* Returns `[dbName, state]` pairs for markers whose state is `in-progress` or `incomplete`
|
|
120
133
|
* (a `clear` result means the marker was removed concurrently and the database is loadable).
|
|
121
134
|
*/
|
|
@@ -41,17 +41,26 @@ const rocksdb_js_1 = require("@harperfast/rocksdb-js");
|
|
|
41
41
|
* duration of a restore, and briefly by `dropDatabase` so the two serialize on the same primitive.
|
|
42
42
|
* Known limitation: the lock is owned by the process, so if the restore job's worker *thread*
|
|
43
43
|
* dies without the process exiting, the lock stays held (restores 409) until Harper restarts.
|
|
44
|
-
* - `<meta-dir>/<key>.restoring` — the completion marker.
|
|
45
|
-
* acquired and before the destructive restore begins; deleted only after
|
|
46
|
-
* successfully, while still holding the lock. Its *existence* means "a
|
|
47
|
-
* not finished successfully". Its first line records the database
|
|
48
|
-
*
|
|
44
|
+
* - `<meta-dir>/<key>.restoring` — the completion marker. Published (temp → fsync → rename → parent
|
|
45
|
+
* fsync) after the lock is acquired and before the destructive restore begins; deleted only after
|
|
46
|
+
* the restore completes successfully, while still holding the lock. Its *existence* means "a
|
|
47
|
+
* restore started and has not finished successfully". Its first line records the database
|
|
48
|
+
* directory name as a fallback so the startup scan can map a marker whose database directory is
|
|
49
|
+
* missing without decoding the hashed key.
|
|
50
|
+
*
|
|
51
|
+
* The rename is what makes the marker trustworthy: the marker path only ever holds the previous
|
|
52
|
+
* content or the complete new content, so a torn write can never replace a valid marker with one
|
|
53
|
+
* the scan reads as empty (and therefore honors as no block). An intact marker is also never
|
|
54
|
+
* rewritten at all — see `beginRestore`.
|
|
49
55
|
*/
|
|
50
56
|
// The backtick makes this an illegal database name (schemaRegex rejects `/` and backtick only), so
|
|
51
57
|
// it can never collide with a real database directory — see the module header.
|
|
52
58
|
exports.RESTORE_META_DIR = '`restore`';
|
|
53
59
|
exports.RESTORE_LOCK_SUFFIX = '.lock';
|
|
54
60
|
exports.RESTORING_MARKER_SUFFIX = '.restoring';
|
|
61
|
+
// Deliberately not a `.restoring` suffix: `scanBlockedRestores` selects markers by that suffix, and
|
|
62
|
+
// a half-written temp must never be mistaken for one.
|
|
63
|
+
const MARKER_TEMP_SUFFIX = '.tmp';
|
|
55
64
|
/**
|
|
56
65
|
* Directory holding the restore metadata for a database — the reserved `` `restore` `` sibling of
|
|
57
66
|
* the database directory (see the module header for why the name contains a backtick). Shared by
|
|
@@ -159,17 +168,29 @@ function releaseRestoreLock(lock) {
|
|
|
159
168
|
(0, rocksdb_js_1.fileLockRelease)(lock.token);
|
|
160
169
|
}
|
|
161
170
|
/**
|
|
162
|
-
*
|
|
163
|
-
*
|
|
164
|
-
* a
|
|
165
|
-
*
|
|
171
|
+
* Whether a marker on disk still blocks the database it belongs to. `scanBlockedRestores` maps a
|
|
172
|
+
* marker to a database by its first line, so the line has to be the whole name: a torn write that
|
|
173
|
+
* left a prefix of it ("ord" for "orders") is non-empty and reads as valid, but blocks a database
|
|
174
|
+
* that does not exist while the real one loads.
|
|
166
175
|
*/
|
|
167
|
-
function
|
|
168
|
-
const markerPath = restoringMarkerPath(dbPath);
|
|
169
|
-
const preexisting = (0, node_fs_1.existsSync)(markerPath);
|
|
170
|
-
const lock = acquireRestoreLock(dbPath);
|
|
176
|
+
function markerIsIntact(markerPath, dbPath) {
|
|
171
177
|
try {
|
|
172
|
-
|
|
178
|
+
return (0, node_fs_1.readFileSync)(markerPath, 'utf8').split('\n', 1)[0] === (0, node_path_1.basename)(dbPath);
|
|
179
|
+
}
|
|
180
|
+
catch {
|
|
181
|
+
return false;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Publish the restoring marker atomically. The caller must already hold the restore lock, which is
|
|
186
|
+
* what makes the fixed temp name safe: only one writer per database can exist at a time, so a temp
|
|
187
|
+
* left by an earlier crash is this database's own debris and is simply overwritten.
|
|
188
|
+
*/
|
|
189
|
+
function publishRestoringMarker(dbPath) {
|
|
190
|
+
const metaDir = restoreMetaDir(dbPath);
|
|
191
|
+
const tempPath = (0, node_path_1.join)(metaDir, restoreMetaKey(dbPath) + MARKER_TEMP_SUFFIX);
|
|
192
|
+
try {
|
|
193
|
+
const fd = (0, node_fs_1.openSync)(tempPath, 'w');
|
|
173
194
|
try {
|
|
174
195
|
// first line is the database directory name so the startup scan can map this marker back to
|
|
175
196
|
// the database it blocks without reversing the hashed key
|
|
@@ -179,9 +200,47 @@ function beginRestore(dbPath) {
|
|
|
179
200
|
finally {
|
|
180
201
|
(0, node_fs_1.closeSync)(fd);
|
|
181
202
|
}
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
203
|
+
(0, node_fs_1.renameSync)(tempPath, restoringMarkerPath(dbPath));
|
|
204
|
+
}
|
|
205
|
+
catch (error) {
|
|
206
|
+
try {
|
|
207
|
+
(0, node_fs_1.unlinkSync)(tempPath);
|
|
208
|
+
}
|
|
209
|
+
catch {
|
|
210
|
+
// debris either way; the write failure is the error worth reporting
|
|
211
|
+
}
|
|
212
|
+
throw error;
|
|
213
|
+
}
|
|
214
|
+
// fsync the metadata directory so the marker's directory entry is durable — without this a
|
|
215
|
+
// power loss can lose the entry, and a half-purged database would load as healthy
|
|
216
|
+
fsyncDir(metaDir);
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Acquire the per-database restore lock and ensure the restoring marker is in place. Call before any
|
|
220
|
+
* destructive step. Returns the lock (with `preexisting` set when a marker was already present, so
|
|
221
|
+
* a failed recovery attempt knows not to clear it). Throws (statusCode 409) if another restore
|
|
222
|
+
* already holds the lock.
|
|
223
|
+
*
|
|
224
|
+
* An intact marker is left exactly as it is. A recovery attempt runs over a directory an earlier
|
|
225
|
+
* restore may have half-purged, so the marker it finds is the only thing keeping that directory
|
|
226
|
+
* from loading as healthy; rewriting it buys nothing (the content it would write is the content
|
|
227
|
+
* already there) and risks everything.
|
|
228
|
+
*/
|
|
229
|
+
function beginRestore(dbPath) {
|
|
230
|
+
const markerPath = restoringMarkerPath(dbPath);
|
|
231
|
+
const lock = acquireRestoreLock(dbPath);
|
|
232
|
+
// Sampled while holding the lock, not before it: a restore that waited out an earlier one would
|
|
233
|
+
// otherwise carry the earlier run's "no marker" reading, and on its own pre-destruction failure
|
|
234
|
+
// clear the marker protecting a directory that run had already half-purged.
|
|
235
|
+
const preexisting = (0, node_fs_1.existsSync)(markerPath);
|
|
236
|
+
try {
|
|
237
|
+
if (!preexisting || !markerIsIntact(markerPath, dbPath))
|
|
238
|
+
publishRestoringMarker(dbPath);
|
|
239
|
+
// An intact marker is kept, but its durability is not assumed: the publisher that wrote it may
|
|
240
|
+
// have been interrupted between the rename and this flush, which would leave the directory
|
|
241
|
+
// entry — the thing the startup scan reads — still only in the page cache.
|
|
242
|
+
else
|
|
243
|
+
fsyncDir(restoreMetaDir(dbPath));
|
|
185
244
|
}
|
|
186
245
|
catch (error) {
|
|
187
246
|
(0, rocksdb_js_1.fileLockRelease)(lock.token);
|
|
@@ -230,8 +289,10 @@ function clearRestoreMarker(lock) {
|
|
|
230
289
|
}
|
|
231
290
|
}
|
|
232
291
|
/**
|
|
233
|
-
* Scan a databases root's reserved `` `restore` `` metadata directory and report every database
|
|
234
|
-
*
|
|
292
|
+
* Scan a databases root's reserved `` `restore` `` metadata directory and report every database
|
|
293
|
+
* currently blocked from loading. Existing database entries are mapped to markers by their hashed
|
|
294
|
+
* keys, so corrupt marker contents cannot unblock them; the first line remains the fallback for a
|
|
295
|
+
* marker whose database directory is missing.
|
|
235
296
|
* Returns `[dbName, state]` pairs for markers whose state is `in-progress` or `incomplete`
|
|
236
297
|
* (a `clear` result means the marker was removed concurrently and the database is loadable).
|
|
237
298
|
*/
|
|
@@ -239,19 +300,25 @@ function scanBlockedRestores(databasesRoot) {
|
|
|
239
300
|
const metaDir = (0, node_path_1.join)(databasesRoot, exports.RESTORE_META_DIR);
|
|
240
301
|
if (!(0, node_fs_1.existsSync)(metaDir))
|
|
241
302
|
return [];
|
|
303
|
+
const databaseNamesByMarker = new Map((0, node_fs_1.readdirSync)(databasesRoot, { withFileTypes: true })
|
|
304
|
+
.filter((entry) => entry.name !== exports.RESTORE_META_DIR)
|
|
305
|
+
.map((entry) => [restoreMetaKey((0, node_path_1.join)(databasesRoot, entry.name)) + exports.RESTORING_MARKER_SUFFIX, entry.name]));
|
|
242
306
|
const blocked = [];
|
|
243
307
|
for (const entry of (0, node_fs_1.readdirSync)(metaDir, { withFileTypes: true })) {
|
|
244
308
|
if (!entry.isFile() || !entry.name.endsWith(exports.RESTORING_MARKER_SUFFIX))
|
|
245
309
|
continue;
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
310
|
+
const markerPath = (0, node_path_1.join)(metaDir, entry.name);
|
|
311
|
+
let dbName = databaseNamesByMarker.get(entry.name);
|
|
312
|
+
if (!dbName) {
|
|
313
|
+
try {
|
|
314
|
+
dbName = (0, node_fs_1.readFileSync)(markerPath, 'utf8').split('\n', 1)[0];
|
|
315
|
+
}
|
|
316
|
+
catch {
|
|
317
|
+
continue; // marker removed concurrently
|
|
318
|
+
}
|
|
319
|
+
if (!dbName || restoringMarkerPath((0, node_path_1.join)(databasesRoot, dbName)) !== markerPath)
|
|
320
|
+
continue;
|
|
252
321
|
}
|
|
253
|
-
if (!dbName)
|
|
254
|
-
continue;
|
|
255
322
|
const state = checkRestoreState((0, node_path_1.join)(databasesRoot, dbName));
|
|
256
323
|
if (state !== 'clear')
|
|
257
324
|
blocked.push([dbName, state]);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"restoreMarker.js","sourceRoot":"","sources":["../../dataLayer/restoreMarker.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;;;
|
|
1
|
+
{"version":3,"file":"restoreMarker.js","sourceRoot":"","sources":["../../dataLayer/restoreMarker.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ export { RequestTarget } from './resources/RequestTarget.ts';
|
|
|
2
2
|
export { flushDatabases } from './resources/databases.ts';
|
|
3
3
|
export { registerReplicatedApplyFailureListener, unregisterReplicatedApplyFailureListener, type ReplicatedApplyFailure, type ReplicatedApplyFailureListener, } from './resources/replicatedApplyFailure.ts';
|
|
4
4
|
export { getContext, getResponse, getUser } from './security/jsLoader.ts';
|
|
5
|
+
export { markCredentialRejection, credentialRejectionError } from './security/credentialRejection.ts';
|
|
5
6
|
export { defineTable, types } from './resources/defineTable.ts';
|
|
6
7
|
export { defineResource, t, schemaOf, projectTableFragment } from './resources/defineResource.ts';
|
|
7
8
|
export type { Query, Context, Session, SourceContext, SubscriptionRequest, RecordLockOptions, RequestTargetOrId, ResourceInterface, WritableRecord, } from './resources/ResourceInterface.ts';
|
package/dist/index.js
CHANGED
|
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.projectTableFragment = exports.schemaOf = exports.t = exports.defineResource = exports.types = exports.defineTable = exports.getUser = exports.getResponse = exports.getContext = exports.unregisterReplicatedApplyFailureListener = exports.registerReplicatedApplyFailureListener = exports.flushDatabases = exports.RequestTarget = void 0;
|
|
6
|
+
exports.projectTableFragment = exports.schemaOf = exports.t = exports.defineResource = exports.types = exports.defineTable = exports.credentialRejectionError = exports.markCredentialRejection = exports.getUser = exports.getResponse = exports.getContext = exports.unregisterReplicatedApplyFailureListener = exports.registerReplicatedApplyFailureListener = exports.flushDatabases = exports.RequestTarget = void 0;
|
|
7
7
|
// Prevents server from starting in worker threads if this was directly imported from a non-server user thread
|
|
8
8
|
const node_worker_threads_1 = __importDefault(require("node:worker_threads"));
|
|
9
9
|
if (!node_worker_threads_1.default.isMainThread) {
|
|
@@ -24,6 +24,11 @@ var jsLoader_ts_1 = require("./security/jsLoader.js");
|
|
|
24
24
|
Object.defineProperty(exports, "getContext", { enumerable: true, get: function () { return jsLoader_ts_1.getContext; } });
|
|
25
25
|
Object.defineProperty(exports, "getResponse", { enumerable: true, get: function () { return jsLoader_ts_1.getResponse; } });
|
|
26
26
|
Object.defineProperty(exports, "getUser", { enumerable: true, get: function () { return jsLoader_ts_1.getUser; } });
|
|
27
|
+
// An untagged error from a `server.getUser` override is treated as an internal fault; these tag one
|
|
28
|
+
// as a rejected credential, which authentication defers to the route owner instead (#2703).
|
|
29
|
+
var credentialRejection_ts_1 = require("./security/credentialRejection.js");
|
|
30
|
+
Object.defineProperty(exports, "markCredentialRejection", { enumerable: true, get: function () { return credentialRejection_ts_1.markCredentialRejection; } });
|
|
31
|
+
Object.defineProperty(exports, "credentialRejectionError", { enumerable: true, get: function () { return credentialRejection_ts_1.credentialRejectionError; } });
|
|
27
32
|
// Code-first schema authoring: declare a table as a TypeScript value; the returned
|
|
28
33
|
// handle is the live, registered table class with per-verb shapes inferred from the definition.
|
|
29
34
|
var defineTable_ts_1 = require("./resources/defineTable.js");
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":";;;;;;AAAA,8GAA8G;AAC9G,8EAAgD;AAChD,IAAI,CAAC,6BAAa,CAAC,YAAY,EAAE,CAAC;IACjC,4GAA4G;IAC5G,IAAI,CAAC,6BAAa,CAAC,UAAU;QAAE,6BAAa,CAAC,UAAU,GAAG,EAAE,CAAC;IAC7D,6BAAa,CAAC,UAAU,CAAC,aAAa,GAAG,IAAI,CAAC;AAC/C,CAAC;AAED,oGAAoG;AACpG,iEAA6D;AAApD,iHAAA,aAAa,OAAA;AACtB,yDAA0D;AAAjD,8GAAA,cAAc,OAAA;AACvB,mFAK+C;AAJ9C,mJAAA,sCAAsC,OAAA;AACtC,qJAAA,wCAAwC,OAAA;AAIzC,sDAA0E;AAAjE,yGAAA,UAAU,OAAA;AAAE,0GAAA,WAAW,OAAA;AAAE,sGAAA,OAAO,OAAA;AACzC,mFAAmF;AACnF,gGAAgG;AAChG,6DAAgE;AAAvD,6GAAA,WAAW,OAAA;AAAE,uGAAA,KAAK,OAAA;AAE3B,+EAA+E;AAC/E,qGAAqG;AACrG,2FAA2F;AAC3F,mEAAkG;AAAzF,mHAAA,cAAc,OAAA;AAAE,sGAAA,CAAC,OAAA;AAAE,6GAAA,QAAQ,OAAA;AAAE,yHAAA,oBAAoB,OAAA;AAyJ1D,oEAAoE;AACpE,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC;AAC5B,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC;AAC/B,OAAO,CAAC,SAAS,GAAG,EAAE,CAAC;AACvB,OAAO,CAAC,MAAM,GAAG,EAAE,CAAC;AACpB,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;AAC3B,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC;AAC9B,OAAO,CAAC,QAAQ,GAAG,SAAS,CAAC;AAC7B,OAAO,CAAC,OAAO,GAAG,SAAS,CAAC;AAC5B,OAAO,CAAC,MAAM,GAAG,EAAE,CAAC;AACpB,OAAO,CAAC,MAAM,GAAG,EAAE,CAAC;AACpB,OAAO,CAAC,OAAO,GAAG,EAAE,CAAC;AACrB,OAAO,CAAC,WAAW,GAAG,SAAS,CAAC;AAEhC,yCAAyC;AACzC,gGAAgG;AAChG,oDAAoD;AACpD,sEAA2D;AAE3D,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,yBAAO,CAAC,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":";;;;;;AAAA,8GAA8G;AAC9G,8EAAgD;AAChD,IAAI,CAAC,6BAAa,CAAC,YAAY,EAAE,CAAC;IACjC,4GAA4G;IAC5G,IAAI,CAAC,6BAAa,CAAC,UAAU;QAAE,6BAAa,CAAC,UAAU,GAAG,EAAE,CAAC;IAC7D,6BAAa,CAAC,UAAU,CAAC,aAAa,GAAG,IAAI,CAAC;AAC/C,CAAC;AAED,oGAAoG;AACpG,iEAA6D;AAApD,iHAAA,aAAa,OAAA;AACtB,yDAA0D;AAAjD,8GAAA,cAAc,OAAA;AACvB,mFAK+C;AAJ9C,mJAAA,sCAAsC,OAAA;AACtC,qJAAA,wCAAwC,OAAA;AAIzC,sDAA0E;AAAjE,yGAAA,UAAU,OAAA;AAAE,0GAAA,WAAW,OAAA;AAAE,sGAAA,OAAO,OAAA;AACzC,oGAAoG;AACpG,4FAA4F;AAC5F,4EAAsG;AAA7F,iIAAA,uBAAuB,OAAA;AAAE,kIAAA,wBAAwB,OAAA;AAC1D,mFAAmF;AACnF,gGAAgG;AAChG,6DAAgE;AAAvD,6GAAA,WAAW,OAAA;AAAE,uGAAA,KAAK,OAAA;AAE3B,+EAA+E;AAC/E,qGAAqG;AACrG,2FAA2F;AAC3F,mEAAkG;AAAzF,mHAAA,cAAc,OAAA;AAAE,sGAAA,CAAC,OAAA;AAAE,6GAAA,QAAQ,OAAA;AAAE,yHAAA,oBAAoB,OAAA;AAyJ1D,oEAAoE;AACpE,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC;AAC5B,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC;AAC/B,OAAO,CAAC,SAAS,GAAG,EAAE,CAAC;AACvB,OAAO,CAAC,MAAM,GAAG,EAAE,CAAC;AACpB,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;AAC3B,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC;AAC9B,OAAO,CAAC,QAAQ,GAAG,SAAS,CAAC;AAC7B,OAAO,CAAC,OAAO,GAAG,SAAS,CAAC;AAC5B,OAAO,CAAC,MAAM,GAAG,EAAE,CAAC;AACpB,OAAO,CAAC,MAAM,GAAG,EAAE,CAAC;AACpB,OAAO,CAAC,OAAO,GAAG,EAAE,CAAC;AACrB,OAAO,CAAC,WAAW,GAAG,SAAS,CAAC;AAEhC,yCAAyC;AACzC,gGAAgG;AAChG,oDAAoD;AACpD,sEAA2D;AAE3D,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,yBAAO,CAAC,CAAC"}
|