@undefineds.co/linx 0.2.17 → 0.2.19
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 +3 -6
- package/dist/generated/version.js +1 -1
- package/dist/generated/version.js.map +1 -1
- package/dist/index.js +256 -143
- package/dist/index.js.map +1 -1
- package/dist/lib/account-api.js +1 -1
- package/dist/lib/account-api.js.map +1 -1
- package/dist/lib/account-session.js +1 -1
- package/dist/lib/account-session.js.map +1 -1
- package/dist/lib/ai-command.js +186 -367
- package/dist/lib/ai-command.js.map +1 -1
- package/dist/lib/chat-api.js +177 -19
- package/dist/lib/chat-api.js.map +1 -1
- package/dist/lib/codex-plugin/bridge.js.map +1 -1
- package/dist/lib/codex-plugin/codex-native-proxy.js.map +1 -1
- package/dist/lib/codex-plugin/index.js.map +1 -1
- package/dist/lib/codex-plugin/runner.js.map +1 -1
- package/dist/lib/credentials-store.js +7 -1
- package/dist/lib/credentials-store.js.map +1 -1
- package/dist/lib/default-model.js +1 -0
- package/dist/lib/default-model.js.map +1 -1
- package/dist/lib/login-command.js +33 -10
- package/dist/lib/login-command.js.map +1 -1
- package/dist/lib/models.js +2 -27
- package/dist/lib/models.js.map +1 -1
- package/dist/lib/node-warning-filter.js +34 -0
- package/dist/lib/node-warning-filter.js.map +1 -0
- package/dist/lib/oidc-auth.js +130 -18
- package/dist/lib/oidc-auth.js.map +1 -1
- package/dist/lib/oidc-session-storage.js.map +1 -1
- package/dist/lib/pi-adapter/auth.js +47 -11
- package/dist/lib/pi-adapter/auth.js.map +1 -1
- package/dist/lib/pi-adapter/branding.js +802 -78
- package/dist/lib/pi-adapter/branding.js.map +1 -1
- package/dist/lib/pi-adapter/index.js.map +1 -1
- package/dist/lib/pi-adapter/interactive.js +179 -5
- package/dist/lib/pi-adapter/interactive.js.map +1 -1
- package/dist/lib/pi-adapter/pod-approval.js +8 -0
- package/dist/lib/pi-adapter/pod-approval.js.map +1 -0
- package/dist/lib/pi-adapter/pod-mirror-mapping.js +189 -0
- package/dist/lib/pi-adapter/pod-mirror-mapping.js.map +1 -0
- package/dist/lib/pi-adapter/pod-mirror.js +416 -0
- package/dist/lib/pi-adapter/pod-mirror.js.map +1 -0
- package/dist/lib/pi-adapter/pod-tools.js +104 -0
- package/dist/lib/pi-adapter/pod-tools.js.map +1 -0
- package/dist/lib/pi-adapter/runtime.js +327 -28
- package/dist/lib/pi-adapter/runtime.js.map +1 -1
- package/dist/lib/pi-adapter/session.js +608 -0
- package/dist/lib/pi-adapter/session.js.map +1 -0
- package/dist/lib/pi-adapter/stream.js +154 -4
- package/dist/lib/pi-adapter/stream.js.map +1 -1
- package/dist/lib/pi-adapter/theme.js.map +1 -1
- package/dist/lib/pi-adapter/web-fetch.js +154 -0
- package/dist/lib/pi-adapter/web-fetch.js.map +1 -0
- package/dist/lib/pod-chat-store.js +40 -30
- package/dist/lib/pod-chat-store.js.map +1 -1
- package/dist/lib/pod-data-session.js +110 -0
- package/dist/lib/pod-data-session.js.map +1 -0
- package/dist/lib/profile-identity.js +16 -60
- package/dist/lib/profile-identity.js.map +1 -1
- package/dist/lib/prompt.js.map +1 -1
- package/dist/lib/runtime-target.js +1 -1
- package/dist/lib/runtime-target.js.map +1 -1
- package/dist/lib/solid-auth.js.map +1 -1
- package/dist/lib/thread-utils.js.map +1 -1
- package/dist/lib/watch/archive.js +1 -1
- package/dist/lib/watch/archive.js.map +1 -1
- package/dist/lib/watch/auth.js +1 -1
- package/dist/lib/watch/auth.js.map +1 -1
- package/dist/lib/watch/codex-composer.js.map +1 -1
- package/dist/lib/watch/codex-footer.js.map +1 -1
- package/dist/lib/watch/codex-overlay.js.map +1 -1
- package/dist/lib/watch/codex-request-form.js +1 -1
- package/dist/lib/watch/codex-request-form.js.map +1 -1
- package/dist/lib/watch/codex-request-input.js.map +1 -1
- package/dist/lib/watch/display.js.map +1 -1
- package/dist/lib/watch/format.js.map +1 -1
- package/dist/lib/watch/hooks/claude.js +4 -0
- package/dist/lib/watch/hooks/claude.js.map +1 -1
- package/dist/lib/watch/hooks/codebuddy.js +4 -0
- package/dist/lib/watch/hooks/codebuddy.js.map +1 -1
- package/dist/lib/watch/hooks/codex.js +4 -0
- package/dist/lib/watch/hooks/codex.js.map +1 -1
- package/dist/lib/watch/hooks/index.js.map +1 -1
- package/dist/lib/watch/hooks/shared.js +0 -1
- package/dist/lib/watch/hooks/shared.js.map +1 -1
- package/dist/lib/watch/index.js.map +1 -1
- package/dist/lib/watch/pod-ai.js +29 -37
- package/dist/lib/watch/pod-ai.js.map +1 -1
- package/dist/lib/watch/pod-approval.js +822 -220
- package/dist/lib/watch/pod-approval.js.map +1 -1
- package/dist/lib/watch/pod-persistence.js +214 -106
- package/dist/lib/watch/pod-persistence.js.map +1 -1
- package/dist/lib/watch/runner.js +243 -38
- package/dist/lib/watch/runner.js.map +1 -1
- package/dist/lib/watch/secretary.js +238 -0
- package/dist/lib/watch/secretary.js.map +1 -0
- package/dist/lib/watch/types.js.map +1 -1
- package/dist/watch-cli.js +8 -34
- package/dist/watch-cli.js.map +1 -1
- package/package.json +3 -9
- package/vendor/agent-runtime/dist/acp.d.ts +27 -0
- package/vendor/agent-runtime/dist/acp.js +86 -0
- package/vendor/agent-runtime/dist/companion-model.d.ts +7 -0
- package/vendor/agent-runtime/dist/companion-model.js +12 -0
- package/vendor/agent-runtime/dist/index.d.ts +3 -0
- package/vendor/agent-runtime/dist/index.js +3 -0
- package/vendor/agent-runtime/dist/turn-controller.d.ts +69 -0
- package/vendor/agent-runtime/dist/turn-controller.js +129 -0
- package/vendor/agent-runtime/package.json +11 -0
- package/vendor/client/dist/client/index.d.ts +0 -118
- package/vendor/client/dist/client/index.js +0 -260
- package/vendor/client/dist/index.d.ts +0 -1
- package/vendor/client/dist/index.js +0 -1
- package/vendor/client/dist/watch/index.d.ts +0 -226
- package/vendor/client/dist/watch/index.js +0 -1114
- package/vendor/client/package.json +0 -9
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
function normalizeMentionToken(value) {
|
|
2
|
+
return value.trim().toLowerCase();
|
|
3
|
+
}
|
|
4
|
+
function uniqueStrings(values) {
|
|
5
|
+
return Array.from(new Set(values.filter(Boolean)));
|
|
6
|
+
}
|
|
7
|
+
export function findMentionedGroupAgents(message, agents) {
|
|
8
|
+
const normalizedMessage = message.toLowerCase();
|
|
9
|
+
return agents.filter((agent) => {
|
|
10
|
+
const candidates = uniqueStrings([
|
|
11
|
+
agent.id,
|
|
12
|
+
agent.name,
|
|
13
|
+
...(agent.aliases ?? []),
|
|
14
|
+
]).map(normalizeMentionToken);
|
|
15
|
+
return candidates.some((candidate) => candidate && normalizedMessage.includes(`@${candidate}`));
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
export async function routeGroupTurn(input) {
|
|
19
|
+
const coordinationId = input.coordinationId ?? `group-turn-${Date.now()}`;
|
|
20
|
+
const agents = input.agents.filter((agent) => agent.id && agent.name);
|
|
21
|
+
if (agents.length === 0) {
|
|
22
|
+
return {
|
|
23
|
+
shouldReply: false,
|
|
24
|
+
targetAgentIds: [],
|
|
25
|
+
routedBy: 'none',
|
|
26
|
+
coordinationId,
|
|
27
|
+
reason: 'No AI agent participants are available.',
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
const mentionedAgents = findMentionedGroupAgents(input.latestUserMessage, agents);
|
|
31
|
+
if (mentionedAgents.length > 0) {
|
|
32
|
+
return {
|
|
33
|
+
shouldReply: true,
|
|
34
|
+
targetAgentIds: mentionedAgents.map((agent) => agent.id),
|
|
35
|
+
routedBy: 'mention',
|
|
36
|
+
coordinationId,
|
|
37
|
+
reason: 'User explicitly mentioned one or more AI agents.',
|
|
38
|
+
confidence: 1,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
if (agents.length === 1) {
|
|
42
|
+
return {
|
|
43
|
+
shouldReply: true,
|
|
44
|
+
targetAgentIds: [agents[0].id],
|
|
45
|
+
routedBy: 'single-agent',
|
|
46
|
+
coordinationId,
|
|
47
|
+
reason: 'Only one AI agent is present in the group.',
|
|
48
|
+
confidence: 1,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
if (!input.decide) {
|
|
52
|
+
return {
|
|
53
|
+
shouldReply: false,
|
|
54
|
+
targetAgentIds: [],
|
|
55
|
+
routedBy: 'none',
|
|
56
|
+
coordinationId,
|
|
57
|
+
reason: 'No group turn controller is available for unmentioned multi-agent routing.',
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
const decision = await input.decide({
|
|
61
|
+
latestUserMessage: input.latestUserMessage,
|
|
62
|
+
agents,
|
|
63
|
+
history: input.history ?? [],
|
|
64
|
+
});
|
|
65
|
+
const validAgentIds = new Set(agents.map((agent) => agent.id));
|
|
66
|
+
const targetAgentIds = uniqueStrings(decision.targetAgentIds).filter((id) => validAgentIds.has(id));
|
|
67
|
+
return {
|
|
68
|
+
shouldReply: decision.shouldReply && targetAgentIds.length > 0,
|
|
69
|
+
targetAgentIds,
|
|
70
|
+
routedBy: 'controller',
|
|
71
|
+
coordinationId,
|
|
72
|
+
reason: decision.reason,
|
|
73
|
+
confidence: decision.confidence,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
export const GROUP_AGENT_TURN_RULE = {
|
|
77
|
+
id: 'chat.group.agent-turn',
|
|
78
|
+
trigger: 'user.message',
|
|
79
|
+
targetAgent: 'agent-turn-controller',
|
|
80
|
+
targetRole: 'system',
|
|
81
|
+
context: {
|
|
82
|
+
recentMessages: 24,
|
|
83
|
+
includeToolCalls: false,
|
|
84
|
+
includeToolResults: false,
|
|
85
|
+
includeSystemEvents: false,
|
|
86
|
+
},
|
|
87
|
+
allowedOutputs: ['chat_message'],
|
|
88
|
+
requiresUserVisibleTrace: false,
|
|
89
|
+
};
|
|
90
|
+
export const WATCH_SECRETARY_APPROVAL_RULE = {
|
|
91
|
+
id: 'watch.secretary.approval',
|
|
92
|
+
trigger: 'approval.required',
|
|
93
|
+
targetAgent: 'ai-secretary',
|
|
94
|
+
targetRole: 'secretary',
|
|
95
|
+
requiredCapabilities: ['approval.request', 'approval.options'],
|
|
96
|
+
context: {
|
|
97
|
+
recentMessages: 24,
|
|
98
|
+
includeCurrentApproval: true,
|
|
99
|
+
includeMatchingGrants: true,
|
|
100
|
+
includeToolCalls: true,
|
|
101
|
+
includeToolResults: true,
|
|
102
|
+
includeSystemEvents: false,
|
|
103
|
+
},
|
|
104
|
+
allowedOutputs: ['chat_message', 'approval_decision', 'control_command'],
|
|
105
|
+
allowedControls: ['inject_message', 'pause', 'stop'],
|
|
106
|
+
requiresUserVisibleTrace: true,
|
|
107
|
+
};
|
|
108
|
+
export const WATCH_SECRETARY_INPUT_RULE = {
|
|
109
|
+
id: 'watch.secretary.input',
|
|
110
|
+
trigger: 'input.required',
|
|
111
|
+
targetAgent: 'ai-secretary',
|
|
112
|
+
targetRole: 'secretary',
|
|
113
|
+
requiredCapabilities: ['input.structured'],
|
|
114
|
+
context: {
|
|
115
|
+
recentMessages: 24,
|
|
116
|
+
includeCurrentApproval: false,
|
|
117
|
+
includeMatchingGrants: false,
|
|
118
|
+
includeToolCalls: true,
|
|
119
|
+
includeToolResults: true,
|
|
120
|
+
includeSystemEvents: false,
|
|
121
|
+
},
|
|
122
|
+
allowedOutputs: ['chat_message', 'input_answer', 'control_command'],
|
|
123
|
+
allowedControls: ['inject_message'],
|
|
124
|
+
requiresUserVisibleTrace: true,
|
|
125
|
+
};
|
|
126
|
+
export const DEFAULT_WATCH_SECRETARY_RULES = [
|
|
127
|
+
WATCH_SECRETARY_APPROVAL_RULE,
|
|
128
|
+
WATCH_SECRETARY_INPUT_RULE,
|
|
129
|
+
];
|
|
@@ -1,118 +0,0 @@
|
|
|
1
|
-
export type LinxAuthType = 'client_credentials' | 'oidc_oauth';
|
|
2
|
-
export interface LinxClientConfig {
|
|
3
|
-
url: string;
|
|
4
|
-
webId: string;
|
|
5
|
-
authType: LinxAuthType;
|
|
6
|
-
}
|
|
7
|
-
export interface LinxClientCredentialsSecrets {
|
|
8
|
-
clientId: string;
|
|
9
|
-
clientSecret: string;
|
|
10
|
-
}
|
|
11
|
-
export interface LinxOidcOAuthSecrets {
|
|
12
|
-
oidcRefreshToken: string;
|
|
13
|
-
oidcAccessToken: string;
|
|
14
|
-
oidcExpiresAt: string;
|
|
15
|
-
}
|
|
16
|
-
export type LinxClientSecrets = LinxClientCredentialsSecrets | LinxOidcOAuthSecrets;
|
|
17
|
-
export interface AccountSession {
|
|
18
|
-
url: string;
|
|
19
|
-
email: string;
|
|
20
|
-
token: string;
|
|
21
|
-
webId?: string;
|
|
22
|
-
podUrl?: string;
|
|
23
|
-
createdAt: string;
|
|
24
|
-
}
|
|
25
|
-
export interface LinxAccountControls {
|
|
26
|
-
pod?: string;
|
|
27
|
-
clientCredentials?: string;
|
|
28
|
-
}
|
|
29
|
-
export interface LinxAccountData {
|
|
30
|
-
controls: LinxAccountControls;
|
|
31
|
-
pods: Record<string, string>;
|
|
32
|
-
webIds: Record<string, string>;
|
|
33
|
-
clientCredentials: Record<string, string>;
|
|
34
|
-
}
|
|
35
|
-
export interface LinxClientCredential {
|
|
36
|
-
id: string;
|
|
37
|
-
secret?: string;
|
|
38
|
-
label?: string;
|
|
39
|
-
webId?: string;
|
|
40
|
-
}
|
|
41
|
-
export interface LinxStoredCredentials {
|
|
42
|
-
url: string;
|
|
43
|
-
webId: string;
|
|
44
|
-
authType: LinxAuthType;
|
|
45
|
-
secrets: LinxClientSecrets;
|
|
46
|
-
}
|
|
47
|
-
export type LinxCredentialBootstrapStatus = 'reused' | 'created' | 'recreated';
|
|
48
|
-
export interface LinxWhoAmIField {
|
|
49
|
-
key: 'email' | 'server' | 'webId' | 'pod' | 'session-created-at';
|
|
50
|
-
value: string;
|
|
51
|
-
}
|
|
52
|
-
export interface PerformLinxPasswordLoginInput {
|
|
53
|
-
baseUrl?: string | null;
|
|
54
|
-
fallbackBaseUrl?: string;
|
|
55
|
-
email: string;
|
|
56
|
-
password: string;
|
|
57
|
-
requestedWebId?: string | null;
|
|
58
|
-
credentialName?: string | null;
|
|
59
|
-
existingCredentials?: LinxStoredCredentials | null;
|
|
60
|
-
now?: Date;
|
|
61
|
-
}
|
|
62
|
-
export interface PerformLinxPasswordLoginResult {
|
|
63
|
-
baseUrl: string;
|
|
64
|
-
webId: string;
|
|
65
|
-
account: LinxAccountData;
|
|
66
|
-
session: AccountSession;
|
|
67
|
-
credentialStatus: LinxCredentialBootstrapStatus;
|
|
68
|
-
credentialsToSave?: {
|
|
69
|
-
url: string;
|
|
70
|
-
webId: string;
|
|
71
|
-
authType: 'client_credentials';
|
|
72
|
-
secrets: LinxClientCredentialsSecrets;
|
|
73
|
-
};
|
|
74
|
-
}
|
|
75
|
-
export interface PerformLinxPasswordLoginDependencies {
|
|
76
|
-
checkServer(baseUrl: string): Promise<boolean>;
|
|
77
|
-
login(email: string, password: string, baseUrl: string): Promise<string | null>;
|
|
78
|
-
getAccountData(token: string, baseUrl: string): Promise<LinxAccountData | null>;
|
|
79
|
-
validateClientCredentials?(credentials: LinxStoredCredentials): Promise<boolean>;
|
|
80
|
-
createClientCredentials(token: string, credentialsUrl: string, webId: string, name?: string): Promise<LinxClientCredential | null>;
|
|
81
|
-
}
|
|
82
|
-
export declare const LINX_HOME_DIRNAME = ".linx";
|
|
83
|
-
export declare const LINX_CONFIG_FILE_NAME = "config.json";
|
|
84
|
-
export declare const LINX_SECRETS_FILE_NAME = "secrets.json";
|
|
85
|
-
export declare const LINX_ACCOUNT_SESSION_FILE_NAME = "account.json";
|
|
86
|
-
export declare const LINX_CLOUD_IDENTITY_ORIGIN = "https://id.undefineds.co";
|
|
87
|
-
export declare const LINX_CLOUD_API_ORIGIN = "https://api.undefineds.co";
|
|
88
|
-
export declare const LINX_CLOUD_ACCOUNT_API_BASE_URL = "https://id.undefineds.co/";
|
|
89
|
-
export declare const LINX_CLOUD_RUNTIME_API_BASE_URL = "https://api.undefineds.co/v1";
|
|
90
|
-
export declare const LINX_CLOUD_API_BASE_URL = "https://id.undefineds.co/";
|
|
91
|
-
export declare const LINX_CLOUD_IDENTITY_HOSTS: readonly ["id.undefineds.co"];
|
|
92
|
-
export declare function resolveLinxBaseUrl(url?: string | null, fallbackBaseUrl?: string): string;
|
|
93
|
-
export declare function resolveLinxRuntimeApiBaseUrl(url?: string | null, fallbackBaseUrl?: string): string;
|
|
94
|
-
export declare function resolveLinxCloudAccountBaseUrl(url?: string | null): string;
|
|
95
|
-
export declare function resolveLinxCloudRuntimeApiBaseUrl(url?: string | null): string;
|
|
96
|
-
export declare function resolveLinxCloudApiBaseUrl(url?: string | null): string;
|
|
97
|
-
export declare function isLinxCloudIdentityBaseUrl(url?: string | null): boolean;
|
|
98
|
-
export declare function resolveLinxRuntimeOriginForIssuerUrl(url?: string | null): string;
|
|
99
|
-
export declare function resolveLinxRuntimeApiBaseUrlForIssuerUrl(url?: string | null): string;
|
|
100
|
-
export declare function resolveLinxPodUrl(webId: string): string;
|
|
101
|
-
export declare function resolveLinxPodBaseUrl(webId: string): string;
|
|
102
|
-
export declare function parseLinxClientConfig(raw: unknown): LinxClientConfig | null;
|
|
103
|
-
export declare function isLinxClientCredentialsSecrets(secrets: LinxClientSecrets): secrets is LinxClientCredentialsSecrets;
|
|
104
|
-
export declare function isLinxOidcOAuthSecrets(secrets: LinxClientSecrets): secrets is LinxOidcOAuthSecrets;
|
|
105
|
-
export declare function parseLinxClientSecrets(raw: unknown): LinxClientSecrets | null;
|
|
106
|
-
export declare function parseLinxAccountData(raw: unknown): LinxAccountData | null;
|
|
107
|
-
export declare function parseLinxClientCredential(raw: unknown): LinxClientCredential | null;
|
|
108
|
-
export declare function parseAccountSession(raw: unknown): AccountSession | null;
|
|
109
|
-
export declare function selectLinxAccountWebId(account: LinxAccountData | null, preferredWebId?: string | null): string | null;
|
|
110
|
-
export declare function hasMatchingLinxStoredCredentials(credentials: Pick<LinxStoredCredentials, 'url' | 'webId'> | null | undefined, baseUrl: string, webId: string): boolean;
|
|
111
|
-
export declare function resolveLinxCredentialBootstrapStatus(input: {
|
|
112
|
-
reusedExistingCredentials: boolean;
|
|
113
|
-
hadMatchingStoredCredentials: boolean;
|
|
114
|
-
}): LinxCredentialBootstrapStatus;
|
|
115
|
-
export declare function listLinxWhoAmIFields(session: AccountSession, options?: {
|
|
116
|
-
verbose?: boolean;
|
|
117
|
-
}): LinxWhoAmIField[];
|
|
118
|
-
export declare function performLinxPasswordLogin(input: PerformLinxPasswordLoginInput, deps: PerformLinxPasswordLoginDependencies): Promise<PerformLinxPasswordLoginResult>;
|
|
@@ -1,260 +0,0 @@
|
|
|
1
|
-
export const LINX_HOME_DIRNAME = '.linx';
|
|
2
|
-
export const LINX_CONFIG_FILE_NAME = 'config.json';
|
|
3
|
-
export const LINX_SECRETS_FILE_NAME = 'secrets.json';
|
|
4
|
-
export const LINX_ACCOUNT_SESSION_FILE_NAME = 'account.json';
|
|
5
|
-
export const LINX_CLOUD_IDENTITY_ORIGIN = 'https://id.undefineds.co';
|
|
6
|
-
export const LINX_CLOUD_API_ORIGIN = 'https://api.undefineds.co';
|
|
7
|
-
export const LINX_CLOUD_ACCOUNT_API_BASE_URL = `${LINX_CLOUD_IDENTITY_ORIGIN}/`;
|
|
8
|
-
export const LINX_CLOUD_RUNTIME_API_BASE_URL = `${LINX_CLOUD_API_ORIGIN}/v1`;
|
|
9
|
-
export const LINX_CLOUD_API_BASE_URL = LINX_CLOUD_ACCOUNT_API_BASE_URL;
|
|
10
|
-
export const LINX_CLOUD_IDENTITY_HOSTS = ['id.undefineds.co'];
|
|
11
|
-
function isRecord(value) {
|
|
12
|
-
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
13
|
-
}
|
|
14
|
-
function optionalString(value) {
|
|
15
|
-
return typeof value === 'string' ? value : undefined;
|
|
16
|
-
}
|
|
17
|
-
function parseStringRecord(value) {
|
|
18
|
-
if (!isRecord(value)) {
|
|
19
|
-
return {};
|
|
20
|
-
}
|
|
21
|
-
const entries = Object.entries(value)
|
|
22
|
-
.filter((entry) => typeof entry[1] === 'string');
|
|
23
|
-
return Object.fromEntries(entries);
|
|
24
|
-
}
|
|
25
|
-
function normalizeAuthType(value) {
|
|
26
|
-
return value === 'oidc_oauth' ? 'oidc_oauth' : 'client_credentials';
|
|
27
|
-
}
|
|
28
|
-
function trimTrailingSlash(url) {
|
|
29
|
-
return url.replace(/\/+$/, '');
|
|
30
|
-
}
|
|
31
|
-
function resolveHostname(url) {
|
|
32
|
-
try {
|
|
33
|
-
return new URL(url).hostname;
|
|
34
|
-
}
|
|
35
|
-
catch {
|
|
36
|
-
return '';
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
export function resolveLinxBaseUrl(url, fallbackBaseUrl = 'http://localhost:3000') {
|
|
40
|
-
const raw = typeof url === 'string' && url.trim() ? url.trim() : fallbackBaseUrl;
|
|
41
|
-
return raw.endsWith('/') ? raw : `${raw}/`;
|
|
42
|
-
}
|
|
43
|
-
export function resolveLinxRuntimeApiBaseUrl(url, fallbackBaseUrl = LINX_CLOUD_ACCOUNT_API_BASE_URL) {
|
|
44
|
-
const normalized = trimTrailingSlash(resolveLinxBaseUrl(url, fallbackBaseUrl));
|
|
45
|
-
return normalized.endsWith('/v1') ? normalized : `${normalized}/v1`;
|
|
46
|
-
}
|
|
47
|
-
export function resolveLinxCloudAccountBaseUrl(url) {
|
|
48
|
-
return resolveLinxBaseUrl(url, LINX_CLOUD_ACCOUNT_API_BASE_URL);
|
|
49
|
-
}
|
|
50
|
-
export function resolveLinxCloudRuntimeApiBaseUrl(url) {
|
|
51
|
-
return resolveLinxRuntimeApiBaseUrl(url, LINX_CLOUD_RUNTIME_API_BASE_URL);
|
|
52
|
-
}
|
|
53
|
-
export function resolveLinxCloudApiBaseUrl(url) {
|
|
54
|
-
return resolveLinxCloudAccountBaseUrl(url);
|
|
55
|
-
}
|
|
56
|
-
export function isLinxCloudIdentityBaseUrl(url) {
|
|
57
|
-
const normalized = resolveLinxBaseUrl(url, LINX_CLOUD_ACCOUNT_API_BASE_URL);
|
|
58
|
-
const hostname = resolveHostname(normalized);
|
|
59
|
-
return LINX_CLOUD_IDENTITY_HOSTS.includes(hostname);
|
|
60
|
-
}
|
|
61
|
-
export function resolveLinxRuntimeOriginForIssuerUrl(url) {
|
|
62
|
-
const normalized = trimTrailingSlash(resolveLinxBaseUrl(url, LINX_CLOUD_ACCOUNT_API_BASE_URL));
|
|
63
|
-
if (isLinxCloudIdentityBaseUrl(normalized)) {
|
|
64
|
-
return LINX_CLOUD_API_ORIGIN;
|
|
65
|
-
}
|
|
66
|
-
return normalized;
|
|
67
|
-
}
|
|
68
|
-
export function resolveLinxRuntimeApiBaseUrlForIssuerUrl(url) {
|
|
69
|
-
const runtimeOrigin = resolveLinxRuntimeOriginForIssuerUrl(url);
|
|
70
|
-
return resolveLinxRuntimeApiBaseUrl(runtimeOrigin, LINX_CLOUD_RUNTIME_API_BASE_URL);
|
|
71
|
-
}
|
|
72
|
-
export function resolveLinxPodUrl(webId) {
|
|
73
|
-
try {
|
|
74
|
-
const target = new URL(webId);
|
|
75
|
-
const pathParts = target.pathname.split('/').filter(Boolean);
|
|
76
|
-
return `${target.origin}/${pathParts[0] ?? ''}/`.replace(/\/+$/, '/');
|
|
77
|
-
}
|
|
78
|
-
catch {
|
|
79
|
-
return '';
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
export function resolveLinxPodBaseUrl(webId) {
|
|
83
|
-
return trimTrailingSlash(resolveLinxPodUrl(webId));
|
|
84
|
-
}
|
|
85
|
-
export function parseLinxClientConfig(raw) {
|
|
86
|
-
if (!isRecord(raw) || typeof raw.url !== 'string' || typeof raw.webId !== 'string') {
|
|
87
|
-
return null;
|
|
88
|
-
}
|
|
89
|
-
return {
|
|
90
|
-
url: raw.url,
|
|
91
|
-
webId: raw.webId,
|
|
92
|
-
authType: normalizeAuthType(raw.authType),
|
|
93
|
-
};
|
|
94
|
-
}
|
|
95
|
-
export function isLinxClientCredentialsSecrets(secrets) {
|
|
96
|
-
return 'clientId' in secrets && 'clientSecret' in secrets;
|
|
97
|
-
}
|
|
98
|
-
export function isLinxOidcOAuthSecrets(secrets) {
|
|
99
|
-
return 'oidcRefreshToken' in secrets && 'oidcAccessToken' in secrets && 'oidcExpiresAt' in secrets;
|
|
100
|
-
}
|
|
101
|
-
export function parseLinxClientSecrets(raw) {
|
|
102
|
-
if (!isRecord(raw)) {
|
|
103
|
-
return null;
|
|
104
|
-
}
|
|
105
|
-
if (typeof raw.clientId === 'string' && typeof raw.clientSecret === 'string') {
|
|
106
|
-
return {
|
|
107
|
-
clientId: raw.clientId,
|
|
108
|
-
clientSecret: raw.clientSecret,
|
|
109
|
-
};
|
|
110
|
-
}
|
|
111
|
-
if (typeof raw.oidcRefreshToken === 'string'
|
|
112
|
-
&& typeof raw.oidcAccessToken === 'string'
|
|
113
|
-
&& typeof raw.oidcExpiresAt === 'string') {
|
|
114
|
-
return {
|
|
115
|
-
oidcRefreshToken: raw.oidcRefreshToken,
|
|
116
|
-
oidcAccessToken: raw.oidcAccessToken,
|
|
117
|
-
oidcExpiresAt: raw.oidcExpiresAt,
|
|
118
|
-
};
|
|
119
|
-
}
|
|
120
|
-
return null;
|
|
121
|
-
}
|
|
122
|
-
export function parseLinxAccountData(raw) {
|
|
123
|
-
if (!isRecord(raw)) {
|
|
124
|
-
return null;
|
|
125
|
-
}
|
|
126
|
-
const controls = isRecord(raw.controls) ? raw.controls : {};
|
|
127
|
-
const accountControls = isRecord(controls.account) ? controls.account : controls;
|
|
128
|
-
return {
|
|
129
|
-
controls: {
|
|
130
|
-
pod: optionalString(accountControls.pod),
|
|
131
|
-
clientCredentials: optionalString(accountControls.clientCredentials),
|
|
132
|
-
},
|
|
133
|
-
pods: parseStringRecord(raw.pods),
|
|
134
|
-
webIds: parseStringRecord(raw.webIds),
|
|
135
|
-
clientCredentials: parseStringRecord(raw.clientCredentials),
|
|
136
|
-
};
|
|
137
|
-
}
|
|
138
|
-
export function parseLinxClientCredential(raw) {
|
|
139
|
-
if (!isRecord(raw) || typeof raw.id !== 'string') {
|
|
140
|
-
return null;
|
|
141
|
-
}
|
|
142
|
-
return {
|
|
143
|
-
id: raw.id,
|
|
144
|
-
label: optionalString(raw.label),
|
|
145
|
-
secret: optionalString(raw.secret),
|
|
146
|
-
webId: optionalString(raw.webId),
|
|
147
|
-
};
|
|
148
|
-
}
|
|
149
|
-
export function parseAccountSession(raw) {
|
|
150
|
-
if (!isRecord(raw)
|
|
151
|
-
|| typeof raw.url !== 'string'
|
|
152
|
-
|| typeof raw.email !== 'string'
|
|
153
|
-
|| typeof raw.token !== 'string'
|
|
154
|
-
|| typeof raw.createdAt !== 'string') {
|
|
155
|
-
return null;
|
|
156
|
-
}
|
|
157
|
-
return {
|
|
158
|
-
url: raw.url,
|
|
159
|
-
email: raw.email,
|
|
160
|
-
token: raw.token,
|
|
161
|
-
webId: optionalString(raw.webId),
|
|
162
|
-
podUrl: optionalString(raw.podUrl),
|
|
163
|
-
createdAt: raw.createdAt,
|
|
164
|
-
};
|
|
165
|
-
}
|
|
166
|
-
export function selectLinxAccountWebId(account, preferredWebId) {
|
|
167
|
-
if (typeof preferredWebId === 'string' && preferredWebId.trim()) {
|
|
168
|
-
return preferredWebId.trim();
|
|
169
|
-
}
|
|
170
|
-
if (!account) {
|
|
171
|
-
return null;
|
|
172
|
-
}
|
|
173
|
-
return Object.keys(account.webIds)[0] ?? null;
|
|
174
|
-
}
|
|
175
|
-
export function hasMatchingLinxStoredCredentials(credentials, baseUrl, webId) {
|
|
176
|
-
return credentials?.url === baseUrl && credentials?.webId === webId;
|
|
177
|
-
}
|
|
178
|
-
export function resolveLinxCredentialBootstrapStatus(input) {
|
|
179
|
-
if (input.reusedExistingCredentials) {
|
|
180
|
-
return 'reused';
|
|
181
|
-
}
|
|
182
|
-
return input.hadMatchingStoredCredentials ? 'recreated' : 'created';
|
|
183
|
-
}
|
|
184
|
-
export function listLinxWhoAmIFields(session, options = {}) {
|
|
185
|
-
const fields = [
|
|
186
|
-
{ key: 'email', value: session.email },
|
|
187
|
-
{ key: 'server', value: session.url },
|
|
188
|
-
];
|
|
189
|
-
if (session.webId) {
|
|
190
|
-
fields.push({ key: 'webId', value: session.webId });
|
|
191
|
-
}
|
|
192
|
-
if (options.verbose && session.podUrl) {
|
|
193
|
-
fields.push({ key: 'pod', value: session.podUrl });
|
|
194
|
-
}
|
|
195
|
-
fields.push({ key: 'session-created-at', value: session.createdAt });
|
|
196
|
-
return fields;
|
|
197
|
-
}
|
|
198
|
-
export async function performLinxPasswordLogin(input, deps) {
|
|
199
|
-
const baseUrl = resolveLinxBaseUrl(input.baseUrl, input.fallbackBaseUrl);
|
|
200
|
-
if (!(await deps.checkServer(baseUrl))) {
|
|
201
|
-
throw new Error(`Cannot reach server at ${baseUrl}`);
|
|
202
|
-
}
|
|
203
|
-
const token = await deps.login(input.email, input.password, baseUrl);
|
|
204
|
-
if (!token) {
|
|
205
|
-
throw new Error('Login failed.');
|
|
206
|
-
}
|
|
207
|
-
const account = await deps.getAccountData(token, baseUrl);
|
|
208
|
-
if (!account) {
|
|
209
|
-
throw new Error('Failed to load account data after login.');
|
|
210
|
-
}
|
|
211
|
-
const webId = selectLinxAccountWebId(account, input.requestedWebId);
|
|
212
|
-
if (!webId) {
|
|
213
|
-
throw new Error('No WebID found. Pass --web-id explicitly.');
|
|
214
|
-
}
|
|
215
|
-
const hadMatchingStoredCredentials = hasMatchingLinxStoredCredentials(input.existingCredentials, baseUrl, webId);
|
|
216
|
-
const existingCredentialsValid = hadMatchingStoredCredentials && input.existingCredentials?.authType === 'client_credentials'
|
|
217
|
-
? await deps.validateClientCredentials?.(input.existingCredentials)
|
|
218
|
-
: false;
|
|
219
|
-
const reusedExistingCredentials = hadMatchingStoredCredentials
|
|
220
|
-
&& input.existingCredentials?.authType === 'client_credentials'
|
|
221
|
-
&& existingCredentialsValid === true;
|
|
222
|
-
const credentialStatus = resolveLinxCredentialBootstrapStatus({
|
|
223
|
-
reusedExistingCredentials,
|
|
224
|
-
hadMatchingStoredCredentials,
|
|
225
|
-
});
|
|
226
|
-
let credentialsToSave;
|
|
227
|
-
if (!reusedExistingCredentials) {
|
|
228
|
-
if (!account.controls.clientCredentials) {
|
|
229
|
-
throw new Error('Cannot find client credentials endpoint.');
|
|
230
|
-
}
|
|
231
|
-
const credential = await deps.createClientCredentials(token, account.controls.clientCredentials, webId, input.credentialName ?? undefined);
|
|
232
|
-
if (!credential?.id || !credential.secret) {
|
|
233
|
-
throw new Error('Failed to create local client credentials.');
|
|
234
|
-
}
|
|
235
|
-
credentialsToSave = {
|
|
236
|
-
url: baseUrl,
|
|
237
|
-
webId,
|
|
238
|
-
authType: 'client_credentials',
|
|
239
|
-
secrets: {
|
|
240
|
-
clientId: credential.id,
|
|
241
|
-
clientSecret: credential.secret,
|
|
242
|
-
},
|
|
243
|
-
};
|
|
244
|
-
}
|
|
245
|
-
return {
|
|
246
|
-
baseUrl,
|
|
247
|
-
webId,
|
|
248
|
-
account,
|
|
249
|
-
credentialStatus,
|
|
250
|
-
...(credentialsToSave ? { credentialsToSave } : {}),
|
|
251
|
-
session: {
|
|
252
|
-
url: baseUrl,
|
|
253
|
-
email: input.email,
|
|
254
|
-
token,
|
|
255
|
-
webId,
|
|
256
|
-
podUrl: resolveLinxPodUrl(webId),
|
|
257
|
-
createdAt: (input.now ?? new Date()).toISOString(),
|
|
258
|
-
},
|
|
259
|
-
};
|
|
260
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from './client/index.js';
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from './client/index.js';
|