create-ekka-desktop-app 0.2.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/README.md +137 -0
- package/bin/cli.js +72 -0
- package/package.json +23 -0
- package/template/branding/app.json +6 -0
- package/template/branding/icon.icns +0 -0
- package/template/eslint.config.js +98 -0
- package/template/index.html +29 -0
- package/template/package.json +40 -0
- package/template/src/app/App.tsx +24 -0
- package/template/src/demo/DemoApp.tsx +260 -0
- package/template/src/demo/components/Banner.tsx +82 -0
- package/template/src/demo/components/EmptyState.tsx +61 -0
- package/template/src/demo/components/InfoPopover.tsx +171 -0
- package/template/src/demo/components/InfoTooltip.tsx +76 -0
- package/template/src/demo/components/LearnMore.tsx +98 -0
- package/template/src/demo/components/NodeCredentialsOnboarding.tsx +219 -0
- package/template/src/demo/components/SetupWizard.tsx +48 -0
- package/template/src/demo/components/StatusBadge.tsx +83 -0
- package/template/src/demo/components/index.ts +10 -0
- package/template/src/demo/hooks/index.ts +6 -0
- package/template/src/demo/hooks/useAuditEvents.ts +30 -0
- package/template/src/demo/layout/Shell.tsx +110 -0
- package/template/src/demo/layout/Sidebar.tsx +192 -0
- package/template/src/demo/pages/AuditLogPage.tsx +235 -0
- package/template/src/demo/pages/DocGenPage.tsx +874 -0
- package/template/src/demo/pages/HomeSetupPage.tsx +182 -0
- package/template/src/demo/pages/LoginPage.tsx +192 -0
- package/template/src/demo/pages/PathPermissionsPage.tsx +873 -0
- package/template/src/demo/pages/RunnerPage.tsx +445 -0
- package/template/src/demo/pages/SystemPage.tsx +557 -0
- package/template/src/demo/pages/VaultPage.tsx +805 -0
- package/template/src/ekka/__tests__/demo-backend.test.ts +187 -0
- package/template/src/ekka/audit/index.ts +7 -0
- package/template/src/ekka/audit/store.ts +68 -0
- package/template/src/ekka/audit/types.ts +22 -0
- package/template/src/ekka/auth/client.ts +212 -0
- package/template/src/ekka/auth/index.ts +30 -0
- package/template/src/ekka/auth/storage.ts +114 -0
- package/template/src/ekka/auth/types.ts +67 -0
- package/template/src/ekka/backend/demo.ts +151 -0
- package/template/src/ekka/backend/interface.ts +36 -0
- package/template/src/ekka/config.ts +48 -0
- package/template/src/ekka/constants.ts +143 -0
- package/template/src/ekka/errors.ts +54 -0
- package/template/src/ekka/index.ts +516 -0
- package/template/src/ekka/internal/backend.ts +156 -0
- package/template/src/ekka/internal/index.ts +7 -0
- package/template/src/ekka/ops/auth.ts +29 -0
- package/template/src/ekka/ops/debug.ts +68 -0
- package/template/src/ekka/ops/home.ts +101 -0
- package/template/src/ekka/ops/index.ts +16 -0
- package/template/src/ekka/ops/nodeCredentials.ts +131 -0
- package/template/src/ekka/ops/nodeSession.ts +145 -0
- package/template/src/ekka/ops/paths.ts +183 -0
- package/template/src/ekka/ops/runner.ts +86 -0
- package/template/src/ekka/ops/runtime.ts +31 -0
- package/template/src/ekka/ops/setup.ts +47 -0
- package/template/src/ekka/ops/vault.ts +459 -0
- package/template/src/ekka/ops/workflowRuns.ts +116 -0
- package/template/src/ekka/types.ts +82 -0
- package/template/src/ekka/utils/idempotency.ts +14 -0
- package/template/src/ekka/utils/index.ts +7 -0
- package/template/src/ekka/utils/time.ts +77 -0
- package/template/src/main.tsx +12 -0
- package/template/src/vite-env.d.ts +12 -0
- package/template/src-tauri/Cargo.toml +41 -0
- package/template/src-tauri/build.rs +3 -0
- package/template/src-tauri/capabilities/default.json +11 -0
- package/template/src-tauri/icons/icon.icns +0 -0
- package/template/src-tauri/icons/icon.png +0 -0
- package/template/src-tauri/resources/ekka-engine-bootstrap +0 -0
- package/template/src-tauri/src/bootstrap.rs +37 -0
- package/template/src-tauri/src/commands.rs +1215 -0
- package/template/src-tauri/src/device_secret.rs +111 -0
- package/template/src-tauri/src/engine_process.rs +538 -0
- package/template/src-tauri/src/grants.rs +129 -0
- package/template/src-tauri/src/handlers/home.rs +65 -0
- package/template/src-tauri/src/handlers/mod.rs +7 -0
- package/template/src-tauri/src/handlers/paths.rs +128 -0
- package/template/src-tauri/src/handlers/vault.rs +680 -0
- package/template/src-tauri/src/main.rs +243 -0
- package/template/src-tauri/src/node_auth.rs +858 -0
- package/template/src-tauri/src/node_credentials.rs +541 -0
- package/template/src-tauri/src/node_runner.rs +882 -0
- package/template/src-tauri/src/node_vault_crypto.rs +113 -0
- package/template/src-tauri/src/node_vault_store.rs +267 -0
- package/template/src-tauri/src/ops/auth.rs +50 -0
- package/template/src-tauri/src/ops/home.rs +251 -0
- package/template/src-tauri/src/ops/mod.rs +7 -0
- package/template/src-tauri/src/ops/runtime.rs +21 -0
- package/template/src-tauri/src/state.rs +639 -0
- package/template/src-tauri/src/types.rs +84 -0
- package/template/src-tauri/tauri.conf.json +41 -0
- package/template/tsconfig.json +26 -0
- package/template/tsconfig.tsbuildinfo +1 -0
- package/template/vite.config.ts +34 -0
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Workflow Runs Operations
|
|
3
|
+
*
|
|
4
|
+
* Create and poll workflow runs via Rust proxy.
|
|
5
|
+
* All HTTP is handled by Rust - no fetch() in TS.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { OPS } from '../constants';
|
|
9
|
+
import { _internal, makeRequest } from '../internal';
|
|
10
|
+
import { getAccessToken } from '../auth/storage';
|
|
11
|
+
|
|
12
|
+
// =============================================================================
|
|
13
|
+
// TYPES
|
|
14
|
+
// =============================================================================
|
|
15
|
+
|
|
16
|
+
export interface WorkflowRunCreateRequest {
|
|
17
|
+
type: string;
|
|
18
|
+
confidentiality: 'public' | 'confidential';
|
|
19
|
+
context: {
|
|
20
|
+
prompt_ref: {
|
|
21
|
+
provider: string;
|
|
22
|
+
prompt_slug: string;
|
|
23
|
+
prompt_version: string;
|
|
24
|
+
};
|
|
25
|
+
variables: Record<string, string>;
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface WorkflowRunCreateResponse {
|
|
30
|
+
id: string;
|
|
31
|
+
status: string;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** Debug bundle info (only present for REPORT_INVALID in dev mode) */
|
|
35
|
+
export interface DebugBundleInfo {
|
|
36
|
+
/** Vault URI (e.g., "vault://tmp/telemetry/llm_debug/{tenant}/{run_id}/") */
|
|
37
|
+
debug_bundle_ref: string;
|
|
38
|
+
/** SHA256 hash of raw output */
|
|
39
|
+
raw_output_sha256: string;
|
|
40
|
+
/** Length of raw output in bytes */
|
|
41
|
+
raw_output_len: number;
|
|
42
|
+
/** Files in the bundle */
|
|
43
|
+
files: string[];
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export interface WorkflowRunResult {
|
|
47
|
+
output_text?: string;
|
|
48
|
+
/** Debug bundle info (only present for REPORT_INVALID failures in dev mode) */
|
|
49
|
+
debug_bundle?: DebugBundleInfo;
|
|
50
|
+
[key: string]: unknown;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export interface WorkflowRun {
|
|
54
|
+
id: string;
|
|
55
|
+
type?: string;
|
|
56
|
+
workflow_definition_id?: string;
|
|
57
|
+
status: 'pending' | 'dispatched' | 'running' | 'completed' | 'failed' | 'cancelled';
|
|
58
|
+
progress: number;
|
|
59
|
+
result?: WorkflowRunResult;
|
|
60
|
+
error?: string;
|
|
61
|
+
created_at: string;
|
|
62
|
+
started_at?: string;
|
|
63
|
+
completed_at?: string;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// =============================================================================
|
|
67
|
+
// OPERATIONS
|
|
68
|
+
// =============================================================================
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Create a new workflow run.
|
|
72
|
+
*
|
|
73
|
+
* @param request - Workflow run creation request
|
|
74
|
+
* @returns Created workflow run with ID
|
|
75
|
+
*/
|
|
76
|
+
export async function createWorkflowRun(
|
|
77
|
+
request: WorkflowRunCreateRequest
|
|
78
|
+
): Promise<WorkflowRunCreateResponse> {
|
|
79
|
+
const jwt = getAccessToken();
|
|
80
|
+
|
|
81
|
+
const req = makeRequest(OPS.WORKFLOW_RUNS_CREATE, {
|
|
82
|
+
request,
|
|
83
|
+
jwt,
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
const response = await _internal.request(req);
|
|
87
|
+
|
|
88
|
+
if (!response.ok) {
|
|
89
|
+
throw new Error(response.error?.message || 'Failed to create workflow run');
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return response.result as WorkflowRunCreateResponse;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Get workflow run status and output.
|
|
97
|
+
*
|
|
98
|
+
* @param id - Workflow run ID
|
|
99
|
+
* @returns Workflow run details
|
|
100
|
+
*/
|
|
101
|
+
export async function getWorkflowRun(id: string): Promise<WorkflowRun> {
|
|
102
|
+
const jwt = getAccessToken();
|
|
103
|
+
|
|
104
|
+
const req = makeRequest(OPS.WORKFLOW_RUNS_GET, {
|
|
105
|
+
id,
|
|
106
|
+
jwt,
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
const response = await _internal.request(req);
|
|
110
|
+
|
|
111
|
+
if (!response.ok) {
|
|
112
|
+
throw new Error(response.error?.message || 'Failed to get workflow run');
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return response.result as WorkflowRun;
|
|
116
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* EKKA Type Definitions
|
|
3
|
+
*
|
|
4
|
+
* Core types for the EKKA client library.
|
|
5
|
+
* Only includes types for IMPLEMENTED features.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { CONTRACT_VERSION } from './constants';
|
|
9
|
+
|
|
10
|
+
// =============================================================================
|
|
11
|
+
// CONTRACT TYPES
|
|
12
|
+
// =============================================================================
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Request format for all engine operations.
|
|
16
|
+
*/
|
|
17
|
+
export interface EngineRequest {
|
|
18
|
+
op: string;
|
|
19
|
+
v: number;
|
|
20
|
+
payload: unknown;
|
|
21
|
+
correlationId: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Error detail in response.
|
|
26
|
+
*/
|
|
27
|
+
export interface EngineErrorDetail {
|
|
28
|
+
code: string;
|
|
29
|
+
message: string;
|
|
30
|
+
details?: unknown;
|
|
31
|
+
status?: number;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Response format for all engine operations.
|
|
36
|
+
*/
|
|
37
|
+
export interface EngineResponse {
|
|
38
|
+
ok: boolean;
|
|
39
|
+
result?: unknown;
|
|
40
|
+
error?: EngineErrorDetail;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// =============================================================================
|
|
44
|
+
// CONTRACT HELPERS
|
|
45
|
+
// =============================================================================
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Generate a correlation ID (UUID v4).
|
|
49
|
+
*/
|
|
50
|
+
export function mkCorrelationId(): string {
|
|
51
|
+
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
|
|
52
|
+
const r = (Math.random() * 16) | 0;
|
|
53
|
+
const v = c === 'x' ? r : (r & 0x3) | 0x8;
|
|
54
|
+
return v.toString(16);
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Create an engine request.
|
|
60
|
+
*/
|
|
61
|
+
export function makeRequest(op: string, payload: unknown = {}): EngineRequest {
|
|
62
|
+
return {
|
|
63
|
+
op,
|
|
64
|
+
v: CONTRACT_VERSION,
|
|
65
|
+
payload,
|
|
66
|
+
correlationId: mkCorrelationId(),
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Create a successful response.
|
|
72
|
+
*/
|
|
73
|
+
export function ok<T = unknown>(result: T): EngineResponse {
|
|
74
|
+
return { ok: true, result };
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Create an error response.
|
|
79
|
+
*/
|
|
80
|
+
export function err(code: string, message: string): EngineResponse {
|
|
81
|
+
return { ok: false, error: { code, message } };
|
|
82
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Idempotency Key Utilities
|
|
3
|
+
* Generate unique keys for idempotent operations.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Generate a unique idempotency key.
|
|
8
|
+
* Format: timestamp-random (e.g., "1706284800000-a1b2c3d4e5f6")
|
|
9
|
+
*/
|
|
10
|
+
export function generateIdempotencyKey(): string {
|
|
11
|
+
const timestamp = Date.now();
|
|
12
|
+
const random = Math.random().toString(36).substring(2, 14);
|
|
13
|
+
return `${timestamp}-${random}`;
|
|
14
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Time Formatting Utilities
|
|
3
|
+
* Human-readable time formatting for the EKKA client.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Format a date as relative time (e.g., "2 minutes ago", "in 5 hours").
|
|
8
|
+
*/
|
|
9
|
+
export function formatRelativeTime(date: Date): string {
|
|
10
|
+
const now = new Date();
|
|
11
|
+
const diffMs = date.getTime() - now.getTime();
|
|
12
|
+
const absDiffMs = Math.abs(diffMs);
|
|
13
|
+
const isPast = diffMs < 0;
|
|
14
|
+
|
|
15
|
+
const seconds = Math.floor(absDiffMs / 1000);
|
|
16
|
+
const minutes = Math.floor(seconds / 60);
|
|
17
|
+
const hours = Math.floor(minutes / 60);
|
|
18
|
+
const days = Math.floor(hours / 24);
|
|
19
|
+
|
|
20
|
+
let value: number;
|
|
21
|
+
let unit: string;
|
|
22
|
+
|
|
23
|
+
if (seconds < 60) {
|
|
24
|
+
value = seconds;
|
|
25
|
+
unit = 'second';
|
|
26
|
+
} else if (minutes < 60) {
|
|
27
|
+
value = minutes;
|
|
28
|
+
unit = 'minute';
|
|
29
|
+
} else if (hours < 24) {
|
|
30
|
+
value = hours;
|
|
31
|
+
unit = 'hour';
|
|
32
|
+
} else {
|
|
33
|
+
value = days;
|
|
34
|
+
unit = 'day';
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const plural = value !== 1 ? 's' : '';
|
|
38
|
+
if (isPast) {
|
|
39
|
+
return value === 0 ? 'just now' : `${value} ${unit}${plural} ago`;
|
|
40
|
+
}
|
|
41
|
+
return `in ${value} ${unit}${plural}`;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Format a date as local time string (e.g., "3:45:30 PM").
|
|
46
|
+
*/
|
|
47
|
+
export function formatLocalTime(date: Date): string {
|
|
48
|
+
return date.toLocaleTimeString(undefined, {
|
|
49
|
+
hour: 'numeric',
|
|
50
|
+
minute: '2-digit',
|
|
51
|
+
second: '2-digit',
|
|
52
|
+
hour12: true,
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Format expiry information from an ISO date string.
|
|
58
|
+
* Returns null if the input is invalid.
|
|
59
|
+
*/
|
|
60
|
+
export function formatExpiryInfo(
|
|
61
|
+
expiresAtIso: string
|
|
62
|
+
): { text: string; isExpired: boolean } | null {
|
|
63
|
+
try {
|
|
64
|
+
const expiresAt = new Date(expiresAtIso);
|
|
65
|
+
if (isNaN(expiresAt.getTime())) {
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const now = new Date();
|
|
70
|
+
const isExpired = expiresAt.getTime() < now.getTime();
|
|
71
|
+
const text = formatRelativeTime(expiresAt);
|
|
72
|
+
|
|
73
|
+
return { text, isExpired };
|
|
74
|
+
} catch {
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { StrictMode } from 'react';
|
|
2
|
+
import { createRoot } from 'react-dom/client';
|
|
3
|
+
|
|
4
|
+
// Toggle between DemoApp and App here:
|
|
5
|
+
// import { App } from './app/App';
|
|
6
|
+
import { DemoApp as App } from './demo/DemoApp';
|
|
7
|
+
|
|
8
|
+
createRoot(document.getElementById('root')!).render(
|
|
9
|
+
<StrictMode>
|
|
10
|
+
<App />
|
|
11
|
+
</StrictMode>
|
|
12
|
+
);
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/// <reference types="vite/client" />
|
|
2
|
+
|
|
3
|
+
interface ImportMetaEnv {
|
|
4
|
+
readonly VITE_EKKA_API_URL: string;
|
|
5
|
+
readonly VITE_EKKA_ENGINE_URL: string;
|
|
6
|
+
readonly VITE_DEV_EMAIL: string;
|
|
7
|
+
readonly VITE_DEV_PASSWORD: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
interface ImportMeta {
|
|
11
|
+
readonly env: ImportMetaEnv;
|
|
12
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
[package]
|
|
2
|
+
name = "ekka-desktop-app"
|
|
3
|
+
version = "0.2.0"
|
|
4
|
+
description = "EKKA Desktop Application"
|
|
5
|
+
authors = ["EKKA"]
|
|
6
|
+
edition = "2021"
|
|
7
|
+
|
|
8
|
+
# Prevent inheriting parent workspace
|
|
9
|
+
[workspace]
|
|
10
|
+
|
|
11
|
+
[build-dependencies]
|
|
12
|
+
tauri-build = { version = "2", features = [] }
|
|
13
|
+
|
|
14
|
+
[dependencies]
|
|
15
|
+
tauri = { version = "2", features = [] }
|
|
16
|
+
tauri-plugin-dialog = "2"
|
|
17
|
+
serde = { version = "1", features = ["derive"] }
|
|
18
|
+
serde_json = "1"
|
|
19
|
+
chrono = { version = "0.4", features = ["serde"] }
|
|
20
|
+
ekka-sdk-core = { path = "../../ekka-execution-node-sdk-rust/crates/framework/ekka-sdk-core" }
|
|
21
|
+
ekka-runner-core = { path = "../../ekka-execution-node-sdk-rust/crates/framework/ekka-runner-core" }
|
|
22
|
+
ekka-runner-local = { path = "../../ekka-execution-node-sdk-rust/crates/apps/ekka-runner-local" }
|
|
23
|
+
reqwest = { version = "0.11", features = ["blocking", "json"] }
|
|
24
|
+
uuid = { version = "1.0", features = ["v4"] }
|
|
25
|
+
tokio = { version = "1", features = ["sync"] }
|
|
26
|
+
tracing = "0.1"
|
|
27
|
+
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
|
|
28
|
+
ed25519-dalek = { version = "2.1", features = ["rand_core"] }
|
|
29
|
+
rand = "0.8"
|
|
30
|
+
base64 = "0.22"
|
|
31
|
+
zeroize = { version = "1.7", features = ["derive"] }
|
|
32
|
+
dotenvy = "0.15"
|
|
33
|
+
hex = "0.4"
|
|
34
|
+
anyhow = "1.0"
|
|
35
|
+
|
|
36
|
+
[dev-dependencies]
|
|
37
|
+
tempfile = "3"
|
|
38
|
+
|
|
39
|
+
[features]
|
|
40
|
+
default = ["custom-protocol"]
|
|
41
|
+
custom-protocol = ["tauri/custom-protocol"]
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
//! Home directory bootstrap
|
|
2
|
+
//!
|
|
3
|
+
//! Handles initialization and resolution of the EKKA home directory.
|
|
4
|
+
|
|
5
|
+
use ekka_sdk_core::ekka_home_bootstrap::{BootstrapConfig, EpochSource, HomeBootstrap, HomeStrategy};
|
|
6
|
+
use std::path::PathBuf;
|
|
7
|
+
|
|
8
|
+
/// Standard bootstrap configuration for EKKA Desktop
|
|
9
|
+
pub fn bootstrap_config() -> BootstrapConfig {
|
|
10
|
+
BootstrapConfig {
|
|
11
|
+
app_name: "ekka-desktop".to_string(),
|
|
12
|
+
default_folder_name: ".ekka-desktop".to_string(),
|
|
13
|
+
home_strategy: HomeStrategy::DataHome {
|
|
14
|
+
env_var: "EKKA_DATA_HOME".to_string(),
|
|
15
|
+
},
|
|
16
|
+
marker_filename: ".ekka-marker.json".to_string(),
|
|
17
|
+
keychain_service: "ai.ekka.desktop".to_string(),
|
|
18
|
+
subdirs: vec!["vault".to_string(), "db".to_string(), "tmp".to_string()],
|
|
19
|
+
epoch_source: EpochSource::EnvVar("EKKA_SECURITY_EPOCH".to_string()),
|
|
20
|
+
storage_layout_version: "v1".to_string(),
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/// Resolve the home path without initializing
|
|
25
|
+
pub fn resolve_home_path() -> Result<PathBuf, String> {
|
|
26
|
+
let config = bootstrap_config();
|
|
27
|
+
let bootstrap = HomeBootstrap::new(config).map_err(|e| e.to_string())?;
|
|
28
|
+
Ok(bootstrap.home_path().to_path_buf())
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/// Initialize home directory and return the bootstrap instance
|
|
32
|
+
pub fn initialize_home() -> Result<HomeBootstrap, String> {
|
|
33
|
+
let config = bootstrap_config();
|
|
34
|
+
let bootstrap = HomeBootstrap::new(config).map_err(|e| e.to_string())?;
|
|
35
|
+
bootstrap.initialize().map_err(|e| e.to_string())?;
|
|
36
|
+
Ok(bootstrap)
|
|
37
|
+
}
|