gitspace 0.2.0-rc.1
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/.claude/settings.local.json +21 -0
- package/.gitspace/bundle.json +50 -0
- package/.gitspace/select/01-status.sh +40 -0
- package/.gitspace/setup/01-install-deps.sh +12 -0
- package/.gitspace/setup/02-typecheck.sh +16 -0
- package/AGENTS.md +439 -0
- package/CLAUDE.md +1 -0
- package/LICENSE +25 -0
- package/README.md +607 -0
- package/bin/gssh +62 -0
- package/bun.lock +647 -0
- package/docs/CONNECTION.md +623 -0
- package/docs/GATEWAY-WORKER.md +319 -0
- package/docs/GETTING-STARTED.md +448 -0
- package/docs/GITSPACE-PLATFORM.md +1819 -0
- package/docs/INFRASTRUCTURE.md +1347 -0
- package/docs/PROTOCOL.md +619 -0
- package/docs/QUICKSTART.md +174 -0
- package/docs/RELAY.md +327 -0
- package/docs/REMOTE-DESIGN.md +549 -0
- package/docs/ROADMAP.md +564 -0
- package/docs/SITE_DOCS_FIGMA_MAKE.md +1167 -0
- package/docs/STACK-DESIGN.md +588 -0
- package/docs/UNIFIED_ARCHITECTURE.md +292 -0
- package/experiments/pty-benchmark.ts +148 -0
- package/experiments/pty-latency.ts +100 -0
- package/experiments/router/client.ts +199 -0
- package/experiments/router/protocol.ts +74 -0
- package/experiments/router/router.ts +217 -0
- package/experiments/router/session.ts +180 -0
- package/experiments/router/test.ts +133 -0
- package/experiments/socket-bandwidth.ts +77 -0
- package/homebrew/gitspace.rb +45 -0
- package/landing-page/ATTRIBUTIONS.md +3 -0
- package/landing-page/README.md +11 -0
- package/landing-page/bun.lock +801 -0
- package/landing-page/guidelines/Guidelines.md +61 -0
- package/landing-page/index.html +37 -0
- package/landing-page/package.json +90 -0
- package/landing-page/postcss.config.mjs +15 -0
- package/landing-page/public/_redirects +1 -0
- package/landing-page/public/favicon.png +0 -0
- package/landing-page/src/app/App.tsx +53 -0
- package/landing-page/src/app/components/figma/ImageWithFallback.tsx +27 -0
- package/landing-page/src/app/components/ui/accordion.tsx +66 -0
- package/landing-page/src/app/components/ui/alert-dialog.tsx +157 -0
- package/landing-page/src/app/components/ui/alert.tsx +66 -0
- package/landing-page/src/app/components/ui/aspect-ratio.tsx +11 -0
- package/landing-page/src/app/components/ui/avatar.tsx +53 -0
- package/landing-page/src/app/components/ui/badge.tsx +46 -0
- package/landing-page/src/app/components/ui/breadcrumb.tsx +109 -0
- package/landing-page/src/app/components/ui/button.tsx +57 -0
- package/landing-page/src/app/components/ui/calendar.tsx +75 -0
- package/landing-page/src/app/components/ui/card.tsx +92 -0
- package/landing-page/src/app/components/ui/carousel.tsx +241 -0
- package/landing-page/src/app/components/ui/chart.tsx +353 -0
- package/landing-page/src/app/components/ui/checkbox.tsx +32 -0
- package/landing-page/src/app/components/ui/collapsible.tsx +33 -0
- package/landing-page/src/app/components/ui/command.tsx +177 -0
- package/landing-page/src/app/components/ui/context-menu.tsx +252 -0
- package/landing-page/src/app/components/ui/dialog.tsx +135 -0
- package/landing-page/src/app/components/ui/drawer.tsx +132 -0
- package/landing-page/src/app/components/ui/dropdown-menu.tsx +257 -0
- package/landing-page/src/app/components/ui/form.tsx +168 -0
- package/landing-page/src/app/components/ui/hover-card.tsx +44 -0
- package/landing-page/src/app/components/ui/input-otp.tsx +77 -0
- package/landing-page/src/app/components/ui/input.tsx +21 -0
- package/landing-page/src/app/components/ui/label.tsx +24 -0
- package/landing-page/src/app/components/ui/menubar.tsx +276 -0
- package/landing-page/src/app/components/ui/navigation-menu.tsx +168 -0
- package/landing-page/src/app/components/ui/pagination.tsx +127 -0
- package/landing-page/src/app/components/ui/popover.tsx +48 -0
- package/landing-page/src/app/components/ui/progress.tsx +31 -0
- package/landing-page/src/app/components/ui/radio-group.tsx +45 -0
- package/landing-page/src/app/components/ui/resizable.tsx +56 -0
- package/landing-page/src/app/components/ui/scroll-area.tsx +58 -0
- package/landing-page/src/app/components/ui/select.tsx +189 -0
- package/landing-page/src/app/components/ui/separator.tsx +28 -0
- package/landing-page/src/app/components/ui/sheet.tsx +139 -0
- package/landing-page/src/app/components/ui/sidebar.tsx +726 -0
- package/landing-page/src/app/components/ui/skeleton.tsx +13 -0
- package/landing-page/src/app/components/ui/slider.tsx +63 -0
- package/landing-page/src/app/components/ui/sonner.tsx +25 -0
- package/landing-page/src/app/components/ui/switch.tsx +31 -0
- package/landing-page/src/app/components/ui/table.tsx +116 -0
- package/landing-page/src/app/components/ui/tabs.tsx +66 -0
- package/landing-page/src/app/components/ui/textarea.tsx +18 -0
- package/landing-page/src/app/components/ui/toggle-group.tsx +73 -0
- package/landing-page/src/app/components/ui/toggle.tsx +47 -0
- package/landing-page/src/app/components/ui/tooltip.tsx +61 -0
- package/landing-page/src/app/components/ui/use-mobile.ts +21 -0
- package/landing-page/src/app/components/ui/utils.ts +6 -0
- package/landing-page/src/components/docs/DocsContent.tsx +718 -0
- package/landing-page/src/components/docs/DocsSidebar.tsx +84 -0
- package/landing-page/src/components/landing/CTA.tsx +59 -0
- package/landing-page/src/components/landing/Comparison.tsx +84 -0
- package/landing-page/src/components/landing/FaultyTerminal.tsx +424 -0
- package/landing-page/src/components/landing/Features.tsx +201 -0
- package/landing-page/src/components/landing/Hero.tsx +142 -0
- package/landing-page/src/components/landing/Pricing.tsx +140 -0
- package/landing-page/src/components/landing/Roadmap.tsx +86 -0
- package/landing-page/src/components/landing/Security.tsx +81 -0
- package/landing-page/src/components/landing/TerminalWindow.tsx +27 -0
- package/landing-page/src/components/landing/UseCases.tsx +55 -0
- package/landing-page/src/components/landing/Workflow.tsx +101 -0
- package/landing-page/src/components/layout/DashboardNavbar.tsx +37 -0
- package/landing-page/src/components/layout/Footer.tsx +55 -0
- package/landing-page/src/components/layout/LandingNavbar.tsx +82 -0
- package/landing-page/src/components/ui/badge.tsx +39 -0
- package/landing-page/src/components/ui/breadcrumb.tsx +115 -0
- package/landing-page/src/components/ui/button.tsx +57 -0
- package/landing-page/src/components/ui/card.tsx +79 -0
- package/landing-page/src/components/ui/mock-terminal.tsx +68 -0
- package/landing-page/src/components/ui/separator.tsx +28 -0
- package/landing-page/src/lib/utils.ts +6 -0
- package/landing-page/src/main.tsx +10 -0
- package/landing-page/src/pages/Dashboard.tsx +133 -0
- package/landing-page/src/pages/DocsPage.tsx +79 -0
- package/landing-page/src/pages/LandingPage.tsx +31 -0
- package/landing-page/src/pages/TerminalView.tsx +106 -0
- package/landing-page/src/styles/fonts.css +0 -0
- package/landing-page/src/styles/index.css +3 -0
- package/landing-page/src/styles/tailwind.css +4 -0
- package/landing-page/src/styles/theme.css +181 -0
- package/landing-page/vite.config.ts +19 -0
- package/npm/darwin-arm64/bin/gssh +0 -0
- package/npm/darwin-arm64/package.json +20 -0
- package/package.json +74 -0
- package/scripts/build.ts +284 -0
- package/scripts/release.ts +140 -0
- package/src/__tests__/test-utils.ts +298 -0
- package/src/commands/__tests__/serve-messages.test.ts +190 -0
- package/src/commands/access.ts +298 -0
- package/src/commands/add.ts +452 -0
- package/src/commands/auth.ts +364 -0
- package/src/commands/connect.ts +287 -0
- package/src/commands/directory.ts +16 -0
- package/src/commands/host.ts +396 -0
- package/src/commands/identity.ts +184 -0
- package/src/commands/list.ts +200 -0
- package/src/commands/relay.ts +315 -0
- package/src/commands/remove.ts +241 -0
- package/src/commands/serve.ts +1493 -0
- package/src/commands/share.ts +456 -0
- package/src/commands/status.ts +125 -0
- package/src/commands/switch.ts +353 -0
- package/src/commands/tmux.ts +317 -0
- package/src/core/__tests__/access.test.ts +240 -0
- package/src/core/access.ts +277 -0
- package/src/core/bundle.ts +342 -0
- package/src/core/config.ts +510 -0
- package/src/core/git.ts +317 -0
- package/src/core/github.ts +151 -0
- package/src/core/identity.ts +631 -0
- package/src/core/linear.ts +225 -0
- package/src/core/shell.ts +161 -0
- package/src/core/trusted-relays.ts +315 -0
- package/src/index.ts +821 -0
- package/src/lib/remote-session/index.ts +7 -0
- package/src/lib/remote-session/protocol.ts +267 -0
- package/src/lib/remote-session/session-handler.ts +581 -0
- package/src/lib/remote-session/workspace-scanner.ts +167 -0
- package/src/lib/tmux-lite/README.md +81 -0
- package/src/lib/tmux-lite/cli.ts +796 -0
- package/src/lib/tmux-lite/crypto/__tests__/helpers/handshake-runner.ts +349 -0
- package/src/lib/tmux-lite/crypto/__tests__/helpers/mock-relay.ts +291 -0
- package/src/lib/tmux-lite/crypto/__tests__/helpers/test-identities.ts +142 -0
- package/src/lib/tmux-lite/crypto/__tests__/integration/authorization.integration.test.ts +339 -0
- package/src/lib/tmux-lite/crypto/__tests__/integration/e2e-communication.integration.test.ts +477 -0
- package/src/lib/tmux-lite/crypto/__tests__/integration/error-handling.integration.test.ts +499 -0
- package/src/lib/tmux-lite/crypto/__tests__/integration/handshake.integration.test.ts +371 -0
- package/src/lib/tmux-lite/crypto/__tests__/integration/security.integration.test.ts +573 -0
- package/src/lib/tmux-lite/crypto/access-control.test.ts +512 -0
- package/src/lib/tmux-lite/crypto/access-control.ts +320 -0
- package/src/lib/tmux-lite/crypto/frames.test.ts +262 -0
- package/src/lib/tmux-lite/crypto/frames.ts +141 -0
- package/src/lib/tmux-lite/crypto/handshake.ts +894 -0
- package/src/lib/tmux-lite/crypto/identity.test.ts +220 -0
- package/src/lib/tmux-lite/crypto/identity.ts +286 -0
- package/src/lib/tmux-lite/crypto/index.ts +51 -0
- package/src/lib/tmux-lite/crypto/invites.test.ts +381 -0
- package/src/lib/tmux-lite/crypto/invites.ts +215 -0
- package/src/lib/tmux-lite/crypto/keyexchange.ts +435 -0
- package/src/lib/tmux-lite/crypto/keys.test.ts +58 -0
- package/src/lib/tmux-lite/crypto/keys.ts +47 -0
- package/src/lib/tmux-lite/crypto/secretbox.test.ts +169 -0
- package/src/lib/tmux-lite/crypto/secretbox.ts +124 -0
- package/src/lib/tmux-lite/handshake-handler.ts +451 -0
- package/src/lib/tmux-lite/protocol.test.ts +307 -0
- package/src/lib/tmux-lite/protocol.ts +266 -0
- package/src/lib/tmux-lite/relay-client.ts +506 -0
- package/src/lib/tmux-lite/server.ts +1250 -0
- package/src/lib/tmux-lite/shell-integration.sh +37 -0
- package/src/lib/tmux-lite/terminal-queries.test.ts +54 -0
- package/src/lib/tmux-lite/terminal-queries.ts +49 -0
- package/src/relay/__tests__/e2e-flow.test.ts +1284 -0
- package/src/relay/__tests__/helpers/auth.ts +354 -0
- package/src/relay/__tests__/helpers/ports.ts +51 -0
- package/src/relay/__tests__/protocol-validation.test.ts +265 -0
- package/src/relay/authorization.ts +303 -0
- package/src/relay/embedded-assets.generated.d.ts +15 -0
- package/src/relay/identity.ts +352 -0
- package/src/relay/index.ts +57 -0
- package/src/relay/pipes.test.ts +427 -0
- package/src/relay/pipes.ts +195 -0
- package/src/relay/protocol.ts +804 -0
- package/src/relay/registries.test.ts +437 -0
- package/src/relay/registries.ts +593 -0
- package/src/relay/server.test.ts +1323 -0
- package/src/relay/server.ts +1092 -0
- package/src/relay/signing.ts +238 -0
- package/src/relay/types.ts +69 -0
- package/src/serve/client-session-manager.ts +622 -0
- package/src/serve/daemon.ts +497 -0
- package/src/serve/pty-session.ts +236 -0
- package/src/serve/types.ts +169 -0
- package/src/shared/components/Flow.tsx +453 -0
- package/src/shared/components/Flow.tui.tsx +343 -0
- package/src/shared/components/Flow.web.tsx +442 -0
- package/src/shared/components/Inbox.tsx +446 -0
- package/src/shared/components/Inbox.tui.tsx +262 -0
- package/src/shared/components/Inbox.web.tsx +329 -0
- package/src/shared/components/MachineList.tsx +187 -0
- package/src/shared/components/MachineList.tui.tsx +161 -0
- package/src/shared/components/MachineList.web.tsx +210 -0
- package/src/shared/components/ProjectList.tsx +176 -0
- package/src/shared/components/ProjectList.tui.tsx +109 -0
- package/src/shared/components/ProjectList.web.tsx +143 -0
- package/src/shared/components/SpacesBrowser.tsx +332 -0
- package/src/shared/components/SpacesBrowser.tui.tsx +163 -0
- package/src/shared/components/SpacesBrowser.web.tsx +221 -0
- package/src/shared/components/index.ts +103 -0
- package/src/shared/hooks/index.ts +16 -0
- package/src/shared/hooks/useNavigation.ts +226 -0
- package/src/shared/index.ts +122 -0
- package/src/shared/providers/LocalMachineProvider.ts +425 -0
- package/src/shared/providers/MachineProvider.ts +165 -0
- package/src/shared/providers/RemoteMachineProvider.ts +444 -0
- package/src/shared/providers/index.ts +26 -0
- package/src/shared/types.ts +145 -0
- package/src/tui/adapters.ts +120 -0
- package/src/tui/app.tsx +1816 -0
- package/src/tui/components/Terminal.tsx +580 -0
- package/src/tui/hooks/index.ts +35 -0
- package/src/tui/hooks/useAppState.ts +314 -0
- package/src/tui/hooks/useDaemonStatus.ts +174 -0
- package/src/tui/hooks/useInboxTUI.ts +113 -0
- package/src/tui/hooks/useRemoteMachines.ts +209 -0
- package/src/tui/index.ts +24 -0
- package/src/tui/state.ts +299 -0
- package/src/tui/terminal-bracketed-paste.test.ts +45 -0
- package/src/tui/terminal-bracketed-paste.ts +47 -0
- package/src/types/bundle.ts +112 -0
- package/src/types/config.ts +89 -0
- package/src/types/errors.ts +206 -0
- package/src/types/identity.ts +284 -0
- package/src/types/workspace-fuzzy.ts +49 -0
- package/src/types/workspace.ts +151 -0
- package/src/utils/bun-socket-writer.ts +80 -0
- package/src/utils/deps.ts +127 -0
- package/src/utils/fuzzy-match.ts +125 -0
- package/src/utils/logger.ts +127 -0
- package/src/utils/markdown.ts +254 -0
- package/src/utils/onboarding.ts +229 -0
- package/src/utils/prompts.ts +114 -0
- package/src/utils/run-commands.ts +112 -0
- package/src/utils/run-scripts.ts +142 -0
- package/src/utils/sanitize.ts +98 -0
- package/src/utils/secrets.ts +122 -0
- package/src/utils/shell-escape.ts +40 -0
- package/src/utils/utf8.ts +79 -0
- package/src/utils/workspace-state.ts +47 -0
- package/src/web/README.md +73 -0
- package/src/web/bun.lock +575 -0
- package/src/web/eslint.config.js +23 -0
- package/src/web/index.html +16 -0
- package/src/web/package.json +37 -0
- package/src/web/public/vite.svg +1 -0
- package/src/web/src/App.tsx +604 -0
- package/src/web/src/assets/react.svg +1 -0
- package/src/web/src/components/Terminal.tsx +207 -0
- package/src/web/src/hooks/useRelayConnection.ts +224 -0
- package/src/web/src/hooks/useTerminal.ts +699 -0
- package/src/web/src/index.css +55 -0
- package/src/web/src/lib/crypto/__tests__/web-terminal.test.ts +1158 -0
- package/src/web/src/lib/crypto/frames.ts +205 -0
- package/src/web/src/lib/crypto/handshake.ts +396 -0
- package/src/web/src/lib/crypto/identity.ts +128 -0
- package/src/web/src/lib/crypto/keyexchange.ts +246 -0
- package/src/web/src/lib/crypto/relay-signing.ts +53 -0
- package/src/web/src/lib/invite.ts +58 -0
- package/src/web/src/lib/storage/identity-store.ts +94 -0
- package/src/web/src/main.tsx +10 -0
- package/src/web/src/types/identity.ts +45 -0
- package/src/web/tsconfig.app.json +28 -0
- package/src/web/tsconfig.json +7 -0
- package/src/web/tsconfig.node.json +26 -0
- package/src/web/vite.config.ts +31 -0
- package/todo-security.md +92 -0
- package/tsconfig.json +23 -0
- package/worker/.wrangler/state/v3/d1/miniflare-D1DatabaseObject/12b7107e435bf1b9a8713a7f320472a63e543104d633d89a26f8d21f4e4ef182.sqlite +0 -0
- package/worker/.wrangler/state/v3/d1/miniflare-D1DatabaseObject/12b7107e435bf1b9a8713a7f320472a63e543104d633d89a26f8d21f4e4ef182.sqlite-shm +0 -0
- package/worker/.wrangler/state/v3/d1/miniflare-D1DatabaseObject/12b7107e435bf1b9a8713a7f320472a63e543104d633d89a26f8d21f4e4ef182.sqlite-wal +0 -0
- package/worker/.wrangler/state/v3/d1/miniflare-D1DatabaseObject/1a1ac3db1ab86ecf712f90322868a9aabc2c7dc9fe2dfbe94f9b075096276b0f.sqlite +0 -0
- package/worker/.wrangler/state/v3/d1/miniflare-D1DatabaseObject/1a1ac3db1ab86ecf712f90322868a9aabc2c7dc9fe2dfbe94f9b075096276b0f.sqlite-shm +0 -0
- package/worker/.wrangler/state/v3/d1/miniflare-D1DatabaseObject/1a1ac3db1ab86ecf712f90322868a9aabc2c7dc9fe2dfbe94f9b075096276b0f.sqlite-wal +0 -0
- package/worker/bun.lock +237 -0
- package/worker/package.json +22 -0
- package/worker/schema.sql +96 -0
- package/worker/src/handlers/auth.ts +451 -0
- package/worker/src/handlers/subdomains.ts +376 -0
- package/worker/src/handlers/user.ts +98 -0
- package/worker/src/index.ts +70 -0
- package/worker/src/middleware/auth.ts +152 -0
- package/worker/src/services/cloudflare.ts +609 -0
- package/worker/src/types.ts +96 -0
- package/worker/tsconfig.json +15 -0
- package/worker/wrangler.toml +26 -0
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type definitions for Spaces bundle configuration
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Onboarding step types
|
|
7
|
+
*/
|
|
8
|
+
export type OnboardingStepType = 'info' | 'confirm' | 'secret' | 'input';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Base interface for all onboarding steps
|
|
12
|
+
*/
|
|
13
|
+
interface BaseOnboardingStep {
|
|
14
|
+
/** Unique identifier for the step */
|
|
15
|
+
id: string;
|
|
16
|
+
/** Step type */
|
|
17
|
+
type: OnboardingStepType;
|
|
18
|
+
/** Display title for the step */
|
|
19
|
+
title: string;
|
|
20
|
+
/** Description/instructions for the user */
|
|
21
|
+
description: string;
|
|
22
|
+
/** Whether this step is required (default: true) */
|
|
23
|
+
required?: boolean;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Info step - Display information, user just acknowledges
|
|
28
|
+
*/
|
|
29
|
+
export interface InfoStep extends BaseOnboardingStep {
|
|
30
|
+
type: 'info';
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Confirm step - Verify something is installed or done
|
|
35
|
+
*/
|
|
36
|
+
export interface ConfirmStep extends BaseOnboardingStep {
|
|
37
|
+
type: 'confirm';
|
|
38
|
+
/** Command to check if installed (optional) */
|
|
39
|
+
checkCommand?: string;
|
|
40
|
+
/** URL for installation instructions (optional) */
|
|
41
|
+
installUrl?: string;
|
|
42
|
+
/** Confirmation prompt text (default: "Continue?") */
|
|
43
|
+
confirmPrompt?: string;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Secret step - Collect sensitive value (masked input)
|
|
48
|
+
*/
|
|
49
|
+
export interface SecretStep extends BaseOnboardingStep {
|
|
50
|
+
type: 'secret';
|
|
51
|
+
/** Key to store the value under in project config */
|
|
52
|
+
configKey: string;
|
|
53
|
+
/** Validation regex pattern (optional) */
|
|
54
|
+
validationPattern?: string;
|
|
55
|
+
/** Validation error message (optional) */
|
|
56
|
+
validationMessage?: string;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Input step - Collect non-secret value
|
|
61
|
+
*/
|
|
62
|
+
export interface InputStep extends BaseOnboardingStep {
|
|
63
|
+
type: 'input';
|
|
64
|
+
/** Key to store the value under in project config */
|
|
65
|
+
configKey: string;
|
|
66
|
+
/** Default value (optional) */
|
|
67
|
+
defaultValue?: string;
|
|
68
|
+
/** Validation regex pattern (optional) */
|
|
69
|
+
validationPattern?: string;
|
|
70
|
+
/** Validation error message (optional) */
|
|
71
|
+
validationMessage?: string;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export type OnboardingStep = InfoStep | ConfirmStep | SecretStep | InputStep;
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Bundle manifest schema (bundle.json)
|
|
78
|
+
*/
|
|
79
|
+
export interface SpacesBundle {
|
|
80
|
+
/** Bundle schema version */
|
|
81
|
+
version: '1.0';
|
|
82
|
+
/** Bundle name (for display) */
|
|
83
|
+
name: string;
|
|
84
|
+
/** Bundle description (optional) */
|
|
85
|
+
description?: string;
|
|
86
|
+
/** Onboarding steps to run before project setup */
|
|
87
|
+
onboarding?: OnboardingStep[];
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Result of running onboarding steps
|
|
92
|
+
*/
|
|
93
|
+
export interface OnboardingResult {
|
|
94
|
+
/** Values to store in project config */
|
|
95
|
+
configValues: Record<string, string>;
|
|
96
|
+
/** Whether onboarding completed successfully */
|
|
97
|
+
completed: boolean;
|
|
98
|
+
/** Step ID where user cancelled (if applicable) */
|
|
99
|
+
cancelledAt?: string;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Loaded bundle with source information
|
|
104
|
+
*/
|
|
105
|
+
export interface LoadedBundle {
|
|
106
|
+
/** The bundle manifest */
|
|
107
|
+
bundle: SpacesBundle;
|
|
108
|
+
/** Path to the bundle directory (for script copying) */
|
|
109
|
+
bundleDir: string;
|
|
110
|
+
/** Source description for logging */
|
|
111
|
+
source: string;
|
|
112
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type definitions for GitSpace CLI configuration
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Global configuration stored in ~/gitspace/.config.json
|
|
7
|
+
*/
|
|
8
|
+
export interface GlobalConfig {
|
|
9
|
+
/** Name of the currently active project */
|
|
10
|
+
currentProject: string | null;
|
|
11
|
+
/** Path to the projects directory (default: ~/gitspace) */
|
|
12
|
+
projectsDir: string;
|
|
13
|
+
/** Default base branch for new projects (default: "main") */
|
|
14
|
+
defaultBaseBranch: string;
|
|
15
|
+
/** Number of days before a workspace is considered stale (default: 30) */
|
|
16
|
+
staleDays: number;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Information about an applied bundle
|
|
21
|
+
*/
|
|
22
|
+
export interface AppliedBundle {
|
|
23
|
+
/** Bundle name */
|
|
24
|
+
name: string;
|
|
25
|
+
/** Bundle version */
|
|
26
|
+
version: string;
|
|
27
|
+
/** Source of the bundle (path or URL) */
|
|
28
|
+
source: string;
|
|
29
|
+
/** ISO timestamp when bundle was applied */
|
|
30
|
+
appliedAt: string;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Project-specific configuration stored in ~/gitspace/{PROJECT_NAME}/.config.json
|
|
35
|
+
*/
|
|
36
|
+
export interface ProjectConfig {
|
|
37
|
+
/** Project name */
|
|
38
|
+
name: string;
|
|
39
|
+
/** GitHub repository in owner/repo format */
|
|
40
|
+
repository: string;
|
|
41
|
+
/** Base branch for creating worktrees */
|
|
42
|
+
baseBranch: string;
|
|
43
|
+
/** Optional Linear API key for issue integration */
|
|
44
|
+
linearApiKey?: string;
|
|
45
|
+
/** Optional Linear team key for filtering issues (e.g., "ENG") */
|
|
46
|
+
linearTeamKey?: string;
|
|
47
|
+
/** ISO timestamp when project was created */
|
|
48
|
+
createdAt: string;
|
|
49
|
+
/** ISO timestamp when project was last accessed */
|
|
50
|
+
lastAccessed: string;
|
|
51
|
+
/** Custom values collected during bundle onboarding (from input steps) */
|
|
52
|
+
bundleValues?: Record<string, string>;
|
|
53
|
+
/** Keys of secrets stored in OS keychain via Bun.secrets (from secret steps) */
|
|
54
|
+
bundleSecretKeys?: string[];
|
|
55
|
+
/** Information about the bundle that was applied */
|
|
56
|
+
appliedBundle?: AppliedBundle;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Default global configuration values
|
|
61
|
+
*/
|
|
62
|
+
export const DEFAULT_GLOBAL_CONFIG: GlobalConfig = {
|
|
63
|
+
currentProject: null,
|
|
64
|
+
projectsDir: '', // Will be set to ~/gitspace at runtime
|
|
65
|
+
defaultBaseBranch: 'main',
|
|
66
|
+
staleDays: 30,
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Create default project configuration
|
|
71
|
+
*/
|
|
72
|
+
export function createDefaultProjectConfig(
|
|
73
|
+
name: string,
|
|
74
|
+
repository: string,
|
|
75
|
+
baseBranch: string,
|
|
76
|
+
linearApiKey?: string,
|
|
77
|
+
linearTeamKey?: string
|
|
78
|
+
): ProjectConfig {
|
|
79
|
+
const now = new Date().toISOString();
|
|
80
|
+
return {
|
|
81
|
+
name,
|
|
82
|
+
repository,
|
|
83
|
+
baseBranch,
|
|
84
|
+
linearApiKey,
|
|
85
|
+
linearTeamKey,
|
|
86
|
+
createdAt: now,
|
|
87
|
+
lastAccessed: now,
|
|
88
|
+
};
|
|
89
|
+
}
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Custom error types for GitSpace CLI
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export type ErrorCode = 'USER_ERROR' | 'SYSTEM_ERROR' | 'SERVICE_ERROR';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Base error class for GitSpace CLI
|
|
9
|
+
*/
|
|
10
|
+
export class SpacesError extends Error {
|
|
11
|
+
public readonly code: ErrorCode;
|
|
12
|
+
public readonly exitCode: number;
|
|
13
|
+
|
|
14
|
+
constructor(message: string, code: ErrorCode = 'USER_ERROR', exitCode?: number) {
|
|
15
|
+
super(message);
|
|
16
|
+
this.name = 'SpacesError';
|
|
17
|
+
this.code = code;
|
|
18
|
+
|
|
19
|
+
// Set exit code based on error type if not provided
|
|
20
|
+
if (exitCode !== undefined) {
|
|
21
|
+
this.exitCode = exitCode;
|
|
22
|
+
} else {
|
|
23
|
+
switch (code) {
|
|
24
|
+
case 'USER_ERROR':
|
|
25
|
+
this.exitCode = 1;
|
|
26
|
+
break;
|
|
27
|
+
case 'SYSTEM_ERROR':
|
|
28
|
+
this.exitCode = 2;
|
|
29
|
+
break;
|
|
30
|
+
case 'SERVICE_ERROR':
|
|
31
|
+
this.exitCode = 3;
|
|
32
|
+
break;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Maintains proper stack trace for where error was thrown
|
|
37
|
+
Error.captureStackTrace(this, this.constructor);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Error thrown when a dependency is missing
|
|
43
|
+
*/
|
|
44
|
+
export class DependencyError extends SpacesError {
|
|
45
|
+
constructor(message: string) {
|
|
46
|
+
super(message, 'SYSTEM_ERROR', 2);
|
|
47
|
+
this.name = 'DependencyError';
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Error thrown when GitHub CLI is not authenticated
|
|
53
|
+
*/
|
|
54
|
+
export class GitHubAuthError extends SpacesError {
|
|
55
|
+
constructor() {
|
|
56
|
+
super(
|
|
57
|
+
'✗ Error: GitHub CLI is not authenticated\n\nPlease run: gh auth login\n\nThen try again.',
|
|
58
|
+
'SYSTEM_ERROR',
|
|
59
|
+
2
|
|
60
|
+
);
|
|
61
|
+
this.name = 'GitHubAuthError';
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Error thrown when a project already exists
|
|
67
|
+
*/
|
|
68
|
+
export class ProjectExistsError extends SpacesError {
|
|
69
|
+
constructor(projectName: string, projectPath: string) {
|
|
70
|
+
super(
|
|
71
|
+
`✗ Error: Project "${projectName}" already exists\n\nThe directory ${projectPath} already contains a project.\n\nTo use this project:\n gssh switch project ${projectName}\n\nTo remove and recreate:\n gssh remove project ${projectName}\n gssh add project`,
|
|
72
|
+
'USER_ERROR',
|
|
73
|
+
1
|
|
74
|
+
);
|
|
75
|
+
this.name = 'ProjectExistsError';
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Error thrown when a workspace already exists
|
|
81
|
+
*/
|
|
82
|
+
export class WorkspaceExistsError extends SpacesError {
|
|
83
|
+
constructor(workspaceName: string) {
|
|
84
|
+
super(
|
|
85
|
+
`✗ Error: Workspace "${workspaceName}" already exists\n\nTo switch to this workspace:\n gssh switch ${workspaceName}`,
|
|
86
|
+
'USER_ERROR',
|
|
87
|
+
1
|
|
88
|
+
);
|
|
89
|
+
this.name = 'WorkspaceExistsError';
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Error thrown when no project is selected
|
|
95
|
+
*/
|
|
96
|
+
export class NoProjectError extends SpacesError {
|
|
97
|
+
constructor() {
|
|
98
|
+
super(
|
|
99
|
+
'✗ Error: No project selected\n\nPlease add a project first:\n gssh add project\n\nOr switch to an existing project:\n gssh switch project',
|
|
100
|
+
'USER_ERROR',
|
|
101
|
+
1
|
|
102
|
+
);
|
|
103
|
+
this.name = 'NoProjectError';
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// ============================================================================
|
|
108
|
+
// Identity & Access Control Errors
|
|
109
|
+
// ============================================================================
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Error thrown when identity is not initialized
|
|
113
|
+
*/
|
|
114
|
+
export class NoIdentityError extends SpacesError {
|
|
115
|
+
constructor() {
|
|
116
|
+
super(
|
|
117
|
+
'✗ Error: No identity found\n\nInitialize your identity first:\n gssh identity init',
|
|
118
|
+
'USER_ERROR',
|
|
119
|
+
1
|
|
120
|
+
);
|
|
121
|
+
this.name = 'NoIdentityError';
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Error thrown when password is incorrect for keypair decryption
|
|
127
|
+
*/
|
|
128
|
+
export class InvalidPasswordError extends SpacesError {
|
|
129
|
+
constructor() {
|
|
130
|
+
super(
|
|
131
|
+
'✗ Error: Invalid password\n\nThe password you entered is incorrect.',
|
|
132
|
+
'USER_ERROR',
|
|
133
|
+
1
|
|
134
|
+
);
|
|
135
|
+
this.name = 'InvalidPasswordError';
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Error thrown when client is not in access list
|
|
141
|
+
*/
|
|
142
|
+
export class AccessDeniedError extends SpacesError {
|
|
143
|
+
constructor(identityId?: string) {
|
|
144
|
+
const msg = identityId
|
|
145
|
+
? `✗ Error: Access denied for identity ${identityId}\n\nThis identity is not in the access list.`
|
|
146
|
+
: '✗ Error: Access denied\n\nYou are not authorized to connect to this machine.';
|
|
147
|
+
super(msg, 'USER_ERROR', 1);
|
|
148
|
+
this.name = 'AccessDeniedError';
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Error thrown when invite token is invalid or expired
|
|
154
|
+
*/
|
|
155
|
+
export class InvalidInviteError extends SpacesError {
|
|
156
|
+
constructor(reason: string = 'Invalid or expired invite') {
|
|
157
|
+
super(
|
|
158
|
+
`✗ Error: ${reason}\n\nThe invite link may have expired or been revoked.`,
|
|
159
|
+
'USER_ERROR',
|
|
160
|
+
1
|
|
161
|
+
);
|
|
162
|
+
this.name = 'InvalidInviteError';
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Error thrown when handshake protocol fails
|
|
168
|
+
*/
|
|
169
|
+
export class HandshakeFailedError extends SpacesError {
|
|
170
|
+
constructor(reason: string = 'Handshake failed') {
|
|
171
|
+
super(
|
|
172
|
+
`✗ Error: ${reason}\n\nCould not establish secure connection.`,
|
|
173
|
+
'SERVICE_ERROR',
|
|
174
|
+
3
|
|
175
|
+
);
|
|
176
|
+
this.name = 'HandshakeFailedError';
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Error thrown when identity already exists
|
|
182
|
+
*/
|
|
183
|
+
export class IdentityExistsError extends SpacesError {
|
|
184
|
+
constructor() {
|
|
185
|
+
super(
|
|
186
|
+
'✗ Error: Identity already exists\n\nTo overwrite, use:\n gssh identity init --force',
|
|
187
|
+
'USER_ERROR',
|
|
188
|
+
1
|
|
189
|
+
);
|
|
190
|
+
this.name = 'IdentityExistsError';
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Error thrown when public key format is invalid
|
|
196
|
+
*/
|
|
197
|
+
export class InvalidPublicKeyError extends SpacesError {
|
|
198
|
+
constructor(reason: string = 'Invalid public key format') {
|
|
199
|
+
super(
|
|
200
|
+
`✗ Error: ${reason}\n\nPublic keys should be base64-encoded Ed25519 or X25519 keys.`,
|
|
201
|
+
'USER_ERROR',
|
|
202
|
+
1
|
|
203
|
+
);
|
|
204
|
+
this.name = 'InvalidPublicKeyError';
|
|
205
|
+
}
|
|
206
|
+
}
|
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type definitions for identity and access control
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
// ============================================================================
|
|
6
|
+
// Keypair Types
|
|
7
|
+
// ============================================================================
|
|
8
|
+
|
|
9
|
+
/** Ed25519 signing keypair */
|
|
10
|
+
export interface SigningKeypair {
|
|
11
|
+
/** 32-byte public key */
|
|
12
|
+
publicKey: Uint8Array;
|
|
13
|
+
/** 64-byte secret key (includes public key suffix per Ed25519 convention) */
|
|
14
|
+
secretKey: Uint8Array;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/** X25519 key exchange keypair */
|
|
18
|
+
export interface KeyExchangeKeypair {
|
|
19
|
+
/** 32-byte public key */
|
|
20
|
+
publicKey: Uint8Array;
|
|
21
|
+
/** 32-byte private key */
|
|
22
|
+
privateKey: Uint8Array;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// ============================================================================
|
|
26
|
+
// Identity Types
|
|
27
|
+
// ============================================================================
|
|
28
|
+
|
|
29
|
+
/** Complete identity (signing + key exchange) */
|
|
30
|
+
export interface Identity {
|
|
31
|
+
/** Unique identifier derived from signing public key (first 16 chars of base64url) */
|
|
32
|
+
id: string;
|
|
33
|
+
/** Ed25519 keypair for signing */
|
|
34
|
+
signing: SigningKeypair;
|
|
35
|
+
/** X25519 keypair for key exchange */
|
|
36
|
+
keyExchange: KeyExchangeKeypair;
|
|
37
|
+
/** Human-readable label */
|
|
38
|
+
label?: string;
|
|
39
|
+
/** Creation timestamp (Unix ms) */
|
|
40
|
+
createdAt: number;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** Serializable identity for JSON storage (base64 encoded keys) */
|
|
44
|
+
export interface StoredIdentity {
|
|
45
|
+
id: string;
|
|
46
|
+
signingPublicKey: string;
|
|
47
|
+
/** Encrypted with password-derived key */
|
|
48
|
+
signingSecretKey: string;
|
|
49
|
+
keyExchangePublicKey: string;
|
|
50
|
+
/** Encrypted with password-derived key */
|
|
51
|
+
keyExchangePrivateKey: string;
|
|
52
|
+
label?: string;
|
|
53
|
+
createdAt: number;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** Public identity info (safe to share) */
|
|
57
|
+
export interface PublicIdentity {
|
|
58
|
+
id: string;
|
|
59
|
+
signingPublicKey: string;
|
|
60
|
+
keyExchangePublicKey: string;
|
|
61
|
+
label?: string;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// ============================================================================
|
|
65
|
+
// Access Control Types
|
|
66
|
+
// ============================================================================
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Access type for a client
|
|
70
|
+
* - 'full': Complete machine access (browse, create sessions, etc.)
|
|
71
|
+
* - 'session-invite': View-only access to a specific session
|
|
72
|
+
*/
|
|
73
|
+
export type AccessType = 'full' | 'session-invite';
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* @deprecated Use AccessType instead. Kept for backwards compatibility during migration.
|
|
77
|
+
*/
|
|
78
|
+
export interface AccessPermissions {
|
|
79
|
+
/** Can read terminal output */
|
|
80
|
+
read: boolean;
|
|
81
|
+
/** Can send terminal input */
|
|
82
|
+
write: boolean;
|
|
83
|
+
/** Can manage sessions (create/kill) */
|
|
84
|
+
manage: boolean;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/** Helper to convert AccessType to legacy AccessPermissions */
|
|
88
|
+
export function accessTypeToPermissions(accessType: AccessType): AccessPermissions {
|
|
89
|
+
if (accessType === 'full') {
|
|
90
|
+
return { read: true, write: true, manage: true };
|
|
91
|
+
}
|
|
92
|
+
// session-invite is read-only
|
|
93
|
+
return { read: true, write: false, manage: false };
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/** Helper to convert legacy AccessPermissions to AccessType */
|
|
97
|
+
export function permissionsToAccessType(permissions: AccessPermissions): AccessType {
|
|
98
|
+
if (permissions.write || permissions.manage) {
|
|
99
|
+
return 'full';
|
|
100
|
+
}
|
|
101
|
+
return 'session-invite';
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/** Access list entry for authorized public keys */
|
|
105
|
+
export interface AccessEntry {
|
|
106
|
+
/** Identity ID (derived from signing public key) */
|
|
107
|
+
identityId: string;
|
|
108
|
+
/** Public signing key (base64) */
|
|
109
|
+
signingPublicKey: string;
|
|
110
|
+
/** Public key exchange key (base64) */
|
|
111
|
+
keyExchangePublicKey: string;
|
|
112
|
+
/** Human-readable label */
|
|
113
|
+
label?: string;
|
|
114
|
+
/** When access was granted (Unix ms) */
|
|
115
|
+
grantedAt: number;
|
|
116
|
+
/** Access type granted */
|
|
117
|
+
accessType: AccessType;
|
|
118
|
+
/** Optional expiry time (Unix ms) */
|
|
119
|
+
expiresAt?: number;
|
|
120
|
+
/** For session-invite: the specific session ID this grants access to */
|
|
121
|
+
sessionId?: string;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// ============================================================================
|
|
125
|
+
// Invite Token Types
|
|
126
|
+
// ============================================================================
|
|
127
|
+
|
|
128
|
+
/** Signed invite token for sharing access */
|
|
129
|
+
export interface InviteToken {
|
|
130
|
+
/** Token version */
|
|
131
|
+
version: 1;
|
|
132
|
+
/** Machine's identity ID */
|
|
133
|
+
machineId: string;
|
|
134
|
+
/** Machine's public signing key (base64) */
|
|
135
|
+
machineSigningKey: string;
|
|
136
|
+
/** Machine's public key exchange key (base64) */
|
|
137
|
+
machineKeyExchangeKey: string;
|
|
138
|
+
/** Relay URL to connect */
|
|
139
|
+
relayUrl: string;
|
|
140
|
+
/** Access type being granted */
|
|
141
|
+
accessType: AccessType;
|
|
142
|
+
/** For session-invite: the specific session ID */
|
|
143
|
+
sessionId?: string;
|
|
144
|
+
/** Expiry timestamp (Unix ms) */
|
|
145
|
+
expiresAt: number;
|
|
146
|
+
/** Single use? */
|
|
147
|
+
singleUse: boolean;
|
|
148
|
+
/** Signature over token data (base64) */
|
|
149
|
+
signature: string;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/** Options for creating an invite token */
|
|
153
|
+
export interface CreateInviteOptions {
|
|
154
|
+
/** Access type to grant (default: 'session-invite') */
|
|
155
|
+
accessType?: AccessType;
|
|
156
|
+
/** For session-invite: the specific session ID */
|
|
157
|
+
sessionId?: string;
|
|
158
|
+
/** Validity duration in milliseconds */
|
|
159
|
+
validityMs?: number;
|
|
160
|
+
/** Whether invite can only be used once */
|
|
161
|
+
singleUse?: boolean;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// ============================================================================
|
|
165
|
+
// Session Key Types
|
|
166
|
+
// ============================================================================
|
|
167
|
+
|
|
168
|
+
/** Derived session keys from handshake */
|
|
169
|
+
export interface SessionKeys {
|
|
170
|
+
/** Key for encrypting data we send (32 bytes) */
|
|
171
|
+
sendKey: Uint8Array;
|
|
172
|
+
/** Key for decrypting data we receive (32 bytes) */
|
|
173
|
+
receiveKey: Uint8Array;
|
|
174
|
+
/** Session ID (for key rotation tracking) */
|
|
175
|
+
sessionId: string;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// ============================================================================
|
|
179
|
+
// Handshake Message Types
|
|
180
|
+
// ============================================================================
|
|
181
|
+
|
|
182
|
+
/** X3DH handshake initiation message from client */
|
|
183
|
+
export interface X3DHInitMessage {
|
|
184
|
+
/** Protocol version */
|
|
185
|
+
version: 1;
|
|
186
|
+
/** Client's ephemeral X25519 public key (base64) */
|
|
187
|
+
ephemeralKey: string;
|
|
188
|
+
/** Timestamp for replay protection (Unix ms) */
|
|
189
|
+
timestamp: number;
|
|
190
|
+
/** Client nonce (base64, 32 bytes random) */
|
|
191
|
+
clientNonce: string;
|
|
192
|
+
/** Optional: Machine ID hint for routing */
|
|
193
|
+
machineIdHint?: string;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/** X3DH response message from machine */
|
|
197
|
+
export interface X3DHResponseMessage {
|
|
198
|
+
/** Protocol version */
|
|
199
|
+
version: 1;
|
|
200
|
+
/** Machine's identity public key - Ed25519 (base64) */
|
|
201
|
+
identityKey: string;
|
|
202
|
+
/** Machine's key exchange public key - X25519 (base64) */
|
|
203
|
+
keyExchangeKey: string;
|
|
204
|
+
/** Machine's ephemeral X25519 public key (base64) */
|
|
205
|
+
ephemeralKey: string;
|
|
206
|
+
/** Machine's signed pre-key - X25519 (base64) */
|
|
207
|
+
signedPreKey: string;
|
|
208
|
+
/** Signature over signedPreKey using identity key (base64) */
|
|
209
|
+
preKeySignature: string;
|
|
210
|
+
/** Server nonce (base64, 32 bytes random) */
|
|
211
|
+
serverNonce: string;
|
|
212
|
+
/** Timestamp (Unix ms) */
|
|
213
|
+
timestamp: number;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/** Client authentication message */
|
|
217
|
+
export interface X3DHAuthMessage {
|
|
218
|
+
/** Protocol version */
|
|
219
|
+
version: 1;
|
|
220
|
+
/** Client's identity public key - Ed25519 (base64) */
|
|
221
|
+
identityKey: string;
|
|
222
|
+
/** Client's key exchange public key - X25519 (base64) */
|
|
223
|
+
keyExchangeKey: string;
|
|
224
|
+
/** HMAC proof binding client identity to session (base64) */
|
|
225
|
+
identityProof: string;
|
|
226
|
+
/**
|
|
227
|
+
* Ed25519 signature over handshake transcript proving key ownership (base64).
|
|
228
|
+
* Signs: clientEphemeral || serverEphemeral || clientNonce || serverNonce
|
|
229
|
+
* This proves the client possesses the private key for identityKey.
|
|
230
|
+
*/
|
|
231
|
+
identitySignature: string;
|
|
232
|
+
/** Authorization type and data */
|
|
233
|
+
authorization:
|
|
234
|
+
| { type: "access_list" }
|
|
235
|
+
| { type: "invite"; inviteToken: string };
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/** Server authentication/result message */
|
|
239
|
+
export interface X3DHResultMessage {
|
|
240
|
+
/** Protocol version */
|
|
241
|
+
version: 1;
|
|
242
|
+
/** Machine's identity public key (base64) */
|
|
243
|
+
identityKey: string;
|
|
244
|
+
/** HMAC proof binding machine identity to session (base64) */
|
|
245
|
+
identityProof: string;
|
|
246
|
+
/** Authorization result */
|
|
247
|
+
result:
|
|
248
|
+
| { type: "accepted"; accessType: AccessType; sessionId?: string }
|
|
249
|
+
| { type: "rejected"; reason: string };
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/** Handshake state phases */
|
|
253
|
+
export type HandshakePhase =
|
|
254
|
+
| "idle"
|
|
255
|
+
| "awaiting_server_hello"
|
|
256
|
+
| "awaiting_client_auth"
|
|
257
|
+
| "awaiting_server_auth"
|
|
258
|
+
| "established"
|
|
259
|
+
| "failed";
|
|
260
|
+
|
|
261
|
+
/** Handshake result on success */
|
|
262
|
+
export interface X3DHHandshakeResult {
|
|
263
|
+
sessionKeys: SessionKeys;
|
|
264
|
+
peerIdentityId: string;
|
|
265
|
+
accessType: AccessType;
|
|
266
|
+
/** For session-invite: the specific session ID access was granted to */
|
|
267
|
+
sessionId?: string;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
// ============================================================================
|
|
271
|
+
// Machine Identity Types
|
|
272
|
+
// ============================================================================
|
|
273
|
+
|
|
274
|
+
/** Machine identity configuration stored locally */
|
|
275
|
+
export interface MachineIdentity {
|
|
276
|
+
/** Unique machine ID (same as identity.id) */
|
|
277
|
+
machineId: string;
|
|
278
|
+
/** Human-readable machine name */
|
|
279
|
+
machineName: string;
|
|
280
|
+
/** Relay server URL this machine uses */
|
|
281
|
+
relayUrl: string;
|
|
282
|
+
/** ISO timestamp when registered */
|
|
283
|
+
registeredAt: string;
|
|
284
|
+
}
|