@hearthlog/runtime 0.0.0-stage → 0.1.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 +235 -0
- package/package.json +51 -3
- package/src/access/session.ts +223 -0
- package/src/access/user-session.ts +61 -0
- package/src/ai/decisions.ts +89 -0
- package/src/calendar/draft.ts +84 -0
- package/src/calendar/feeds.ts +91 -0
- package/src/calendar/groups.ts +198 -0
- package/src/calendar/logic.ts +141 -0
- package/src/calendar/preferences.ts +40 -0
- package/src/calendar/weeks.ts +56 -0
- package/src/commands/index.ts +184 -0
- package/src/commands/local-commit.ts +214 -0
- package/src/commands/standard.ts +8 -0
- package/src/commands/validation.ts +206 -0
- package/src/db/bootstrap.ts +72 -0
- package/src/db/calendar.ts +638 -0
- package/src/db/dynamic-ddl.ts +127 -0
- package/src/db/entities.ts +208 -0
- package/src/db/history.ts +194 -0
- package/src/db/index.ts +1240 -0
- package/src/db/kv.ts +33 -0
- package/src/db/local-statistics.ts +106 -0
- package/src/db/module-projections.ts +46 -0
- package/src/db/raw-browser.ts +361 -0
- package/src/db/read-repositories.ts +29 -0
- package/src/db/read-session.ts +47 -0
- package/src/db/schema-version.ts +76 -0
- package/src/db/session-context.ts +33 -0
- package/src/event/code-export.ts +65 -0
- package/src/event/dynamic-entities.ts +503 -0
- package/src/event/dynamic-materializer.ts +288 -0
- package/src/event/handlers.ts +490 -0
- package/src/event/index.ts +53 -0
- package/src/event/meta-entity-types.ts +165 -0
- package/src/event/projection-builder.ts +384 -0
- package/src/event/queries.ts +126 -0
- package/src/event/rebuild.ts +176 -0
- package/src/event/reference-lookup.ts +93 -0
- package/src/event/registry.ts +158 -0
- package/src/event/schema-effects.ts +45 -0
- package/src/event/types.ts +20 -0
- package/src/history/action-boundary.ts +18 -0
- package/src/history/action-detail.ts +23 -0
- package/src/history/change-comparison.ts +29 -0
- package/src/history/change-display.ts +41 -0
- package/src/history/contracts.ts +63 -0
- package/src/history/history.ts +372 -0
- package/src/history/legacy-replay.ts +69 -0
- package/src/history/legacy-url.ts +9 -0
- package/src/history/lineage.ts +123 -0
- package/src/history/log-format.ts +17 -0
- package/src/history/log-map.ts +110 -0
- package/src/history/navigation.ts +14 -0
- package/src/history/point-snapshot.ts +229 -0
- package/src/history/timeline.ts +215 -0
- package/src/history/url.ts +18 -0
- package/src/ledger/README.md +118 -0
- package/src/ledger/admin-client.ts +616 -0
- package/src/ledger/client.ts +10 -0
- package/src/ledger/config.ts +117 -0
- package/src/ledger/entity-id.ts +115 -0
- package/src/ledger/errors.ts +144 -0
- package/src/ledger/http-client.ts +590 -0
- package/src/ledger/index.ts +67 -0
- package/src/ledger/socket.ts +400 -0
- package/src/ledger/types.ts +202 -0
- package/src/ledger/version-tracker-singleton.ts +12 -0
- package/src/ledger/version-tracker.ts +259 -0
- package/src/log-management.ts +123 -0
- package/src/log-validation.ts +19 -0
- package/src/native/reminders.ts +2 -0
- package/src/native/shell.svelte.ts +136 -0
- package/src/native/shell.ts +102 -0
- package/src/pwa/registration.ts +169 -0
- package/src/recovery/local-recovery.ts +59 -0
- package/src/recovery/reset-sequence.ts +13 -0
- package/src/runtime/clock.ts +43 -0
- package/src/runtime/kept-page-data.svelte.ts +42 -0
- package/src/runtime/page-data.svelte.ts +160 -0
- package/src/runtime/phone-header.svelte.ts +17 -0
- package/src/runtime/read-coordinator.ts +103 -0
- package/src/runtime/refresh.ts +15 -0
- package/src/runtime/start-page.ts +56 -0
- package/src/runtime/view.ts +83 -0
- package/src/runtime/workspace.ts +62 -0
- package/src/storage/indexeddb-statistics.ts +153 -0
- package/src/store/attention.svelte.ts +51 -0
- package/src/store/conflict-merge.ts +169 -0
- package/src/store/entity-sync-state.svelte.ts +36 -0
- package/src/store/event-log.svelte.ts +109 -0
- package/src/store/events.svelte.ts +14 -0
- package/src/store/local-context.ts +93 -0
- package/src/store/local-store.svelte.ts +58 -0
- package/src/store/log-version.svelte.ts +35 -0
- package/src/store/logs.svelte.ts +60 -0
- package/src/store/moved.svelte.ts +43 -0
- package/src/store/offline-readiness.svelte.ts +188 -0
- package/src/store/outbox-request.ts +61 -0
- package/src/store/outbox.ts +426 -0
- package/src/store/pending-work-transfer.ts +49 -0
- package/src/store/pending-work.ts +143 -0
- package/src/store/sync-coordinator.ts +170 -0
- package/src/store/sync-invalidation.ts +10 -0
- package/src/store/sync-issues.ts +406 -0
- package/src/store/sync-progress.ts +54 -0
- package/src/store/sync-state.ts +127 -0
- package/src/store/sync.svelte.ts +1010 -0
- package/src/store/tab-coordination.ts +164 -0
- package/src/testing/e2e-seed.ts +40 -0
- package/src/testing/local-database.ts +120 -0
- package/src/testing/projection-database.ts +105 -0
- package/src/testing/test-entities.ts +28 -0
- package/src/theme/appearance.svelte.ts +111 -0
- package/src/utils/address.ts +5 -0
- package/src/utils/async.ts +30 -0
- package/src/utils/long-press.ts +70 -0
- package/src/utils/perf-dataset.ts +405 -0
- package/src/utils/perf.ts +627 -0
- package/README.md +0 -3
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration for the Ledger Service client
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export interface RetryPolicy {
|
|
6
|
+
maxRetries: number;
|
|
7
|
+
initialDelayMs: number;
|
|
8
|
+
maxDelayMs: number;
|
|
9
|
+
backoffMultiplier: number;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface LedgerConfig {
|
|
13
|
+
baseUrl: string;
|
|
14
|
+
authToken?: string;
|
|
15
|
+
timeout: number;
|
|
16
|
+
retryPolicy: RetryPolicy;
|
|
17
|
+
enableRealtime: boolean;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Default retry policy with exponential backoff
|
|
22
|
+
*/
|
|
23
|
+
export const DEFAULT_RETRY_POLICY: RetryPolicy = {
|
|
24
|
+
maxRetries: 3,
|
|
25
|
+
initialDelayMs: 1000,
|
|
26
|
+
maxDelayMs: 10000,
|
|
27
|
+
backoffMultiplier: 2
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Validation error thrown when configuration is invalid
|
|
32
|
+
*/
|
|
33
|
+
export class ConfigValidationError extends Error {
|
|
34
|
+
constructor(message: string) {
|
|
35
|
+
super(message);
|
|
36
|
+
this.name = 'ConfigValidationError';
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Validates the Ledger Service configuration
|
|
42
|
+
* @throws {ConfigValidationError} if configuration is invalid
|
|
43
|
+
*/
|
|
44
|
+
function validateConfig(config: Partial<LedgerConfig>): void {
|
|
45
|
+
if (!config.baseUrl) {
|
|
46
|
+
throw new ConfigValidationError('LEDGER_SERVICE_URL is required');
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const isRelative =
|
|
50
|
+
config.baseUrl.startsWith('/') && !config.baseUrl.startsWith('//');
|
|
51
|
+
let isAbsoluteHttp = false;
|
|
52
|
+
if (!isRelative) {
|
|
53
|
+
try {
|
|
54
|
+
const parsed = new URL(config.baseUrl);
|
|
55
|
+
isAbsoluteHttp = parsed.protocol === 'http:' || parsed.protocol === 'https:';
|
|
56
|
+
} catch {
|
|
57
|
+
isAbsoluteHttp = false;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
if (!isRelative && !isAbsoluteHttp) {
|
|
61
|
+
throw new ConfigValidationError(`Invalid LEDGER_SERVICE_URL: ${config.baseUrl}`);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (config.timeout !== undefined && (config.timeout <= 0 || !Number.isFinite(config.timeout))) {
|
|
65
|
+
throw new ConfigValidationError(`Invalid timeout value: ${config.timeout}`);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (config.retryPolicy) {
|
|
69
|
+
const { maxRetries, initialDelayMs, maxDelayMs, backoffMultiplier } = config.retryPolicy;
|
|
70
|
+
|
|
71
|
+
if (maxRetries < 0 || !Number.isInteger(maxRetries)) {
|
|
72
|
+
throw new ConfigValidationError(`Invalid maxRetries: ${maxRetries}`);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (initialDelayMs <= 0 || !Number.isFinite(initialDelayMs)) {
|
|
76
|
+
throw new ConfigValidationError(`Invalid initialDelayMs: ${initialDelayMs}`);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (maxDelayMs <= 0 || !Number.isFinite(maxDelayMs)) {
|
|
80
|
+
throw new ConfigValidationError(`Invalid maxDelayMs: ${maxDelayMs}`);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (backoffMultiplier <= 1 || !Number.isFinite(backoffMultiplier)) {
|
|
84
|
+
throw new ConfigValidationError(`Invalid backoffMultiplier: ${backoffMultiplier}`);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Loads and validates Ledger Service configuration from environment variables
|
|
91
|
+
* @returns {LedgerConfig} Validated configuration object
|
|
92
|
+
* @throws {ConfigValidationError} if configuration is invalid or missing required values
|
|
93
|
+
*/
|
|
94
|
+
export function loadLedgerConfig(): LedgerConfig {
|
|
95
|
+
const baseUrl = import.meta.env.VITE_LEDGER_SERVICE_URL;
|
|
96
|
+
const authToken = import.meta.env.VITE_LEDGER_AUTH_TOKEN;
|
|
97
|
+
const timeoutStr = import.meta.env.VITE_LEDGER_TIMEOUT_MS;
|
|
98
|
+
const maxRetriesStr = import.meta.env.VITE_LEDGER_MAX_RETRIES;
|
|
99
|
+
const enableRealtimeStr = import.meta.env.VITE_LEDGER_ENABLE_REALTIME;
|
|
100
|
+
|
|
101
|
+
const config: LedgerConfig = {
|
|
102
|
+
baseUrl: baseUrl || (import.meta.env.DEV ? 'http://127.0.0.1:8787' : '/api/ledger'),
|
|
103
|
+
authToken: authToken || undefined,
|
|
104
|
+
timeout: timeoutStr ? parseInt(timeoutStr, 10) : 5000,
|
|
105
|
+
retryPolicy: {
|
|
106
|
+
maxRetries: maxRetriesStr ? parseInt(maxRetriesStr, 10) : DEFAULT_RETRY_POLICY.maxRetries,
|
|
107
|
+
initialDelayMs: DEFAULT_RETRY_POLICY.initialDelayMs,
|
|
108
|
+
maxDelayMs: DEFAULT_RETRY_POLICY.maxDelayMs,
|
|
109
|
+
backoffMultiplier: DEFAULT_RETRY_POLICY.backoffMultiplier
|
|
110
|
+
},
|
|
111
|
+
enableRealtime: enableRealtimeStr !== 'false'
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
validateConfig(config);
|
|
115
|
+
|
|
116
|
+
return config;
|
|
117
|
+
}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Entity ID extraction utilities for mapping AppEvent types to entity identifiers.
|
|
3
|
+
* This module implements the entity ID extraction logic using the entity registry.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { ExtendedAppEvent, TombstoneEvent } from '../event/types.js';
|
|
7
|
+
import { isMetaEntityEvent } from '../event/types.js';
|
|
8
|
+
import { entityRegistry } from '../event/registry.js';
|
|
9
|
+
|
|
10
|
+
function inferEntityNameFromEventType(type: string): string | null {
|
|
11
|
+
const match = type.match(/^(.*)_(ADDED|UPDATED|REMOVED)$/);
|
|
12
|
+
return match ? match[1].toLowerCase() : null;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Extracts the entity identifier from an AppEvent.
|
|
17
|
+
*
|
|
18
|
+
* Entity IDs are prefixed with their type to prevent collisions between different entity types
|
|
19
|
+
* and to make debugging easier with self-documenting IDs.
|
|
20
|
+
*
|
|
21
|
+
* Uses the entity registry for dynamic dispatch - no changes needed when adding new entities.
|
|
22
|
+
*
|
|
23
|
+
* Mapping rules:
|
|
24
|
+
* - Entity events: `{entityName}:{payload.id}` (e.g., `asset:123`, `transaction:456`)
|
|
25
|
+
* - Tombstone events: `tombstone:{payload.eventId}`
|
|
26
|
+
*
|
|
27
|
+
* @param event - The AppEvent to extract the entity ID from
|
|
28
|
+
* @returns The entity identifier string
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* ```typescript
|
|
32
|
+
* const event: AddCalendarEventEvent = {
|
|
33
|
+
* id: 'evt-123',
|
|
34
|
+
* type: 'CALENDAR_EVENT_ADDED',
|
|
35
|
+
* timestamp: Date.now(),
|
|
36
|
+
* payload: { id: 'event-456', title: 'Dentist', eventDate: '2026-10-12', startTime: '', notes: '', pinned: false }
|
|
37
|
+
* };
|
|
38
|
+
* const entityId = extractEntityId(event); // Returns: 'asset:asset-456'
|
|
39
|
+
* ```
|
|
40
|
+
*/
|
|
41
|
+
export function extractEntityId(event: ExtendedAppEvent): string {
|
|
42
|
+
// Handle tombstone events specially
|
|
43
|
+
if (event.type === 'EVENT_TOMBSTONED') {
|
|
44
|
+
return `tombstone:${(event as TombstoneEvent).payload.eventId}`;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Excision markers are their own entity so they never join an existing
|
|
48
|
+
// entity's version chain.
|
|
49
|
+
if (event.type === 'EVENTS_EXCISED') {
|
|
50
|
+
return `excision:${event.id}`;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (isMetaEntityEvent(event)) {
|
|
54
|
+
return `entity_type:${event.payload.id}`;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Match the most specific prefix: one entity's prefix can start another's
|
|
58
|
+
// (FOO_ and FOO_BAR_), and definition order must not change event ownership.
|
|
59
|
+
let match: { name: string; prefix: string } | null = null;
|
|
60
|
+
for (const [name, entry] of Object.entries(entityRegistry)) {
|
|
61
|
+
if (event.type.startsWith(entry.eventPrefix) && (!match || entry.eventPrefix.length > match.prefix.length)) {
|
|
62
|
+
match = { name, prefix: entry.eventPrefix };
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
if (match) return `${match.name}:${(event.payload as { id: string }).id}`;
|
|
66
|
+
|
|
67
|
+
const payloadId = (event.payload as { id?: string }).id;
|
|
68
|
+
const inferredEntityName = inferEntityNameFromEventType(event.type);
|
|
69
|
+
if (payloadId && inferredEntityName) {
|
|
70
|
+
return `${inferredEntityName}:${payloadId}`;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Fallback for unknown event types
|
|
74
|
+
return `unknown:${event.id}`;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Extracts entity IDs from a batch of events.
|
|
79
|
+
*
|
|
80
|
+
* @param events - Array of AppEvents
|
|
81
|
+
* @returns Array of entity identifier strings in the same order
|
|
82
|
+
*/
|
|
83
|
+
export function extractEntityIds(events: ExtendedAppEvent[]): string[] {
|
|
84
|
+
return events.map(extractEntityId);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Groups events by their entity ID.
|
|
89
|
+
* Useful for batch operations that need to process events per entity.
|
|
90
|
+
*
|
|
91
|
+
* @param events - Array of AppEvents to group
|
|
92
|
+
* @returns Map of entity ID to array of events for that entity
|
|
93
|
+
*
|
|
94
|
+
* @example
|
|
95
|
+
* ```typescript
|
|
96
|
+
* const events = [assetEvent1, transactionEvent1, assetEvent2];
|
|
97
|
+
* const grouped = groupEventsByEntity(events);
|
|
98
|
+
* // Returns: Map {
|
|
99
|
+
* // 'asset:123' => [assetEvent1, assetEvent2],
|
|
100
|
+
* // 'transaction:456' => [transactionEvent1]
|
|
101
|
+
* // }
|
|
102
|
+
* ```
|
|
103
|
+
*/
|
|
104
|
+
export function groupEventsByEntity(events: ExtendedAppEvent[]): Map<string, ExtendedAppEvent[]> {
|
|
105
|
+
const grouped = new Map<string, ExtendedAppEvent[]>();
|
|
106
|
+
|
|
107
|
+
for (const event of events) {
|
|
108
|
+
const entityId = extractEntityId(event);
|
|
109
|
+
const existing = grouped.get(entityId) || [];
|
|
110
|
+
existing.push(event);
|
|
111
|
+
grouped.set(entityId, existing);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return grouped;
|
|
115
|
+
}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ledger Service Error Classes
|
|
3
|
+
*
|
|
4
|
+
* Custom error types for Ledger Service API operations with:
|
|
5
|
+
* - Proper stack trace capture
|
|
6
|
+
* - Type guard functions for safe narrowing
|
|
7
|
+
* - Error cause chaining support
|
|
8
|
+
* - Discriminator tags for reliable instanceof alternatives
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import type {
|
|
12
|
+
ConflictResponse,
|
|
13
|
+
EntityVersionChainErrorResponse,
|
|
14
|
+
} from "./types.js";
|
|
15
|
+
|
|
16
|
+
// ============================================================================
|
|
17
|
+
// Base Error
|
|
18
|
+
// ============================================================================
|
|
19
|
+
|
|
20
|
+
export interface LedgerErrorOptions {
|
|
21
|
+
cause?: Error;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Base error class for all Ledger Service API errors
|
|
26
|
+
*/
|
|
27
|
+
export class LedgerServiceError extends Error {
|
|
28
|
+
readonly _tag: string = "LedgerServiceError";
|
|
29
|
+
|
|
30
|
+
constructor(
|
|
31
|
+
message: string,
|
|
32
|
+
public readonly statusCode?: number,
|
|
33
|
+
public readonly response?: unknown,
|
|
34
|
+
public readonly code?: string,
|
|
35
|
+
options?: LedgerErrorOptions,
|
|
36
|
+
) {
|
|
37
|
+
super(message, options);
|
|
38
|
+
this.name = "LedgerServiceError";
|
|
39
|
+
Error.captureStackTrace?.(this, this.constructor);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function isLedgerServiceError(e: unknown): e is LedgerServiceError {
|
|
44
|
+
return (
|
|
45
|
+
e instanceof LedgerServiceError ||
|
|
46
|
+
(e as any)?._tag === "LedgerServiceError"
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// ============================================================================
|
|
51
|
+
// Version Conflict Error (HTTP 409)
|
|
52
|
+
// ============================================================================
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Error thrown when a version conflict occurs (HTTP 409)
|
|
56
|
+
*/
|
|
57
|
+
export class VersionConflictError extends LedgerServiceError {
|
|
58
|
+
override readonly _tag = "VersionConflictError";
|
|
59
|
+
|
|
60
|
+
constructor(
|
|
61
|
+
message: string,
|
|
62
|
+
public readonly conflict: ConflictResponse,
|
|
63
|
+
options?: LedgerErrorOptions,
|
|
64
|
+
) {
|
|
65
|
+
super(message, 409, conflict, conflict.code, options);
|
|
66
|
+
this.name = "VersionConflictError";
|
|
67
|
+
Error.captureStackTrace?.(this, this.constructor);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export function isVersionConflictError(e: unknown): e is VersionConflictError {
|
|
72
|
+
return (
|
|
73
|
+
e instanceof VersionConflictError ||
|
|
74
|
+
(e as any)?._tag === "VersionConflictError"
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// ============================================================================
|
|
79
|
+
// Not Found Error (HTTP 404)
|
|
80
|
+
// ============================================================================
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Error thrown when a resource is not found (HTTP 404)
|
|
84
|
+
*/
|
|
85
|
+
export class NotFoundError extends LedgerServiceError {
|
|
86
|
+
override readonly _tag = "NotFoundError";
|
|
87
|
+
|
|
88
|
+
constructor(message: string, code = "not_found", options?: LedgerErrorOptions) {
|
|
89
|
+
super(message, 404, undefined, code, options);
|
|
90
|
+
this.name = "NotFoundError";
|
|
91
|
+
Error.captureStackTrace?.(this, this.constructor);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export function isNotFoundError(e: unknown): e is NotFoundError {
|
|
96
|
+
return e instanceof NotFoundError || (e as any)?._tag === "NotFoundError";
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// ============================================================================
|
|
100
|
+
// Authentication Error (HTTP 401/403)
|
|
101
|
+
// ============================================================================
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Error thrown when authentication fails (HTTP 401/403)
|
|
105
|
+
*/
|
|
106
|
+
export class AuthenticationError extends LedgerServiceError {
|
|
107
|
+
override readonly _tag = "AuthenticationError";
|
|
108
|
+
|
|
109
|
+
constructor(
|
|
110
|
+
message: string,
|
|
111
|
+
statusCode: number,
|
|
112
|
+
code = "unauthorized",
|
|
113
|
+
options?: LedgerErrorOptions,
|
|
114
|
+
) {
|
|
115
|
+
super(message, statusCode, undefined, code, options);
|
|
116
|
+
this.name = "AuthenticationError";
|
|
117
|
+
Error.captureStackTrace?.(this, this.constructor);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
export class EntityVersionChainError extends LedgerServiceError {
|
|
122
|
+
override readonly _tag = "EntityVersionChainError";
|
|
123
|
+
|
|
124
|
+
constructor(public readonly details: EntityVersionChainErrorResponse) {
|
|
125
|
+
super(details.message ?? "Invalid entity version chain", 409, details, details.code);
|
|
126
|
+
this.name = "EntityVersionChainError";
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
export class IdempotencyMismatchError extends LedgerServiceError {
|
|
131
|
+
override readonly _tag = "IdempotencyMismatchError";
|
|
132
|
+
|
|
133
|
+
constructor(response: unknown) {
|
|
134
|
+
super("Request ID was reused with different content", 409, response, "idempotency_mismatch");
|
|
135
|
+
this.name = "IdempotencyMismatchError";
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
export function isAuthenticationError(e: unknown): e is AuthenticationError {
|
|
140
|
+
return (
|
|
141
|
+
e instanceof AuthenticationError ||
|
|
142
|
+
(e as any)?._tag === "AuthenticationError"
|
|
143
|
+
);
|
|
144
|
+
}
|