@xfxstudio/claworld 0.2.12 → 0.2.14
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 +45 -19
- package/index.js +0 -1
- package/openclaw.plugin.json +1 -1
- package/package.json +1 -5
- package/skills/claworld-help/SKILL.md +84 -91
- package/skills/claworld-join-and-chat/SKILL.md +9 -9
- package/src/openclaw/index.js +0 -3
- package/src/openclaw/plugin/account-identity.js +0 -1
- package/src/openclaw/plugin/claworld-channel-plugin.js +8 -253
- package/src/openclaw/plugin/managed-config.js +1 -7
- package/src/openclaw/plugin/onboarding.js +128 -103
- package/src/openclaw/plugin/register.js +183 -232
- package/src/openclaw/plugin/relay-client.js +8 -5
- package/src/openclaw/runtime/product-shell-helper.js +11 -364
- package/src/openclaw/runtime/tool-contracts.js +0 -182
- package/src/openclaw/runtime/tool-inventory.js +4 -27
- package/bin/claworld.mjs +0 -9
- package/src/lib/agent-profile.js +0 -74
- package/src/lib/http-auth.js +0 -151
- package/src/lib/policy.js +0 -114
- package/src/openclaw/installer/cli.js +0 -406
- package/src/openclaw/installer/constants.js +0 -14
- package/src/openclaw/installer/core.js +0 -2122
- package/src/openclaw/installer/doctor.js +0 -876
- package/src/openclaw/installer/workspace-contract.js +0 -427
- package/src/product-shell/agent-cards/card-routes.js +0 -64
- package/src/product-shell/agent-cards/card-service.js +0 -287
- package/src/product-shell/agent-cards/spec-builder.js +0 -167
- package/src/product-shell/agent-cards/storage/image-host-storage.js +0 -192
- package/src/product-shell/agent-cards/storage/local-public-storage.js +0 -74
- package/src/product-shell/agent-cards/svg-renderer.js +0 -325
- package/src/product-shell/agent-cards/template-registry.js +0 -131
- package/src/product-shell/catalog/default-world-catalog.js +0 -38
- package/src/product-shell/contracts/candidate-feed.js +0 -393
- package/src/product-shell/contracts/world-manifest.js +0 -369
- package/src/product-shell/conversation-feedback/conversation-feedback-service.js +0 -261
- package/src/product-shell/feedback/feedback-contract.js +0 -13
- package/src/product-shell/feedback/feedback-routes.js +0 -98
- package/src/product-shell/feedback/feedback-service.js +0 -252
- package/src/product-shell/index.js +0 -212
- package/src/product-shell/matching/matchmaking-service.js +0 -395
- package/src/product-shell/membership/membership-service.js +0 -284
- package/src/product-shell/onboarding/onboarding-routes.js +0 -37
- package/src/product-shell/onboarding/onboarding-service.js +0 -220
- package/src/product-shell/orchestration/world-conversation-orchestrator.js +0 -28
- package/src/product-shell/profile/profile-service.js +0 -142
- package/src/product-shell/profile/public-identity-routes.js +0 -160
- package/src/product-shell/profile/public-identity-service.js +0 -192
- package/src/product-shell/search/search-service.js +0 -393
- package/src/product-shell/social/chat-request-approval-policy.js +0 -332
- package/src/product-shell/social/chat-request-routes.js +0 -130
- package/src/product-shell/social/chat-request-service.js +0 -723
- package/src/product-shell/social/friend-routes.js +0 -82
- package/src/product-shell/social/friend-service.js +0 -557
- package/src/product-shell/social/social-routes.js +0 -21
- package/src/product-shell/social/social-service.js +0 -136
- package/src/product-shell/worlds/world-admin-service.js +0 -486
- package/src/product-shell/worlds/world-authorization.js +0 -136
- package/src/product-shell/worlds/world-broadcast-service.js +0 -296
- package/src/product-shell/worlds/world-routes.js +0 -403
- package/src/product-shell/worlds/world-service.js +0 -89
- package/src/product-shell/worlds/world-text.js +0 -75
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import { authenticateAppTokenRequest } from '../../lib/http-auth.js';
|
|
2
|
-
|
|
3
|
-
function sendOnboardingError(res, error) {
|
|
4
|
-
const status = Number.isInteger(error?.status) ? error.status : 500;
|
|
5
|
-
if (error?.responseBody && typeof error.responseBody === 'object') {
|
|
6
|
-
return res.status(status).json(error.responseBody);
|
|
7
|
-
}
|
|
8
|
-
const code = typeof error?.code === 'string' ? error.code : 'internal_error';
|
|
9
|
-
return res.status(status).json({ error: code, message: error?.message || code });
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export function registerOnboardingRoutes(app, { onboardingService, store = null }) {
|
|
13
|
-
app.get('/v1/meta/install', (_req, res) => {
|
|
14
|
-
res.json(onboardingService.getInstallManifest());
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
app.get('/v1/onboarding/plan', (req, res) => {
|
|
18
|
-
res.json(onboardingService.getFirstRunPlan({ worldId: req.query.worldId }));
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
app.post('/v1/onboarding/activate', (req, res) => {
|
|
22
|
-
const auth = authenticateAppTokenRequest({ store, req });
|
|
23
|
-
if (auth.present && !auth.ok) {
|
|
24
|
-
return res.status(401).json(auth.error);
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
try {
|
|
28
|
-
const result = onboardingService.activateInstallation({
|
|
29
|
-
auth,
|
|
30
|
-
input: req.body || {},
|
|
31
|
-
});
|
|
32
|
-
return res.status(result.created ? 201 : 200).json(result);
|
|
33
|
-
} catch (error) {
|
|
34
|
-
return sendOnboardingError(res, error);
|
|
35
|
-
}
|
|
36
|
-
});
|
|
37
|
-
}
|
|
@@ -1,220 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
CLAWORLD_DOCTOR_COMMAND,
|
|
3
|
-
CLAWORLD_INSTALLER_COMMAND,
|
|
4
|
-
CLAWORLD_INSTALLER_PACKAGE_NAME,
|
|
5
|
-
CLAWORLD_OPENCLAW_MIN_HOST_VERSION,
|
|
6
|
-
CLAWORLD_UNINSTALL_COMMAND,
|
|
7
|
-
CLAWORLD_UPDATE_COMMAND,
|
|
8
|
-
} from '../../openclaw/installer/constants.js';
|
|
9
|
-
|
|
10
|
-
const DEFAULT_INSTALL_CHANNEL_ID = 'claworld';
|
|
11
|
-
const DEFAULT_INSTALL_ACCOUNT_ID = 'claworld';
|
|
12
|
-
const DEFAULT_INSTALL_LOCAL_AGENT_ID = 'main';
|
|
13
|
-
const DEFAULT_ACTIVATION_DISPLAY_NAME = 'Claworld Agent';
|
|
14
|
-
|
|
15
|
-
function normalizeText(value, fallback = null) {
|
|
16
|
-
if (value == null) return fallback;
|
|
17
|
-
const normalized = String(value).trim();
|
|
18
|
-
return normalized || fallback;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
function projectRecommendedWorld(world = {}) {
|
|
22
|
-
return {
|
|
23
|
-
worldId: world.worldId,
|
|
24
|
-
displayName: world.displayName,
|
|
25
|
-
summary: world.summary,
|
|
26
|
-
category: world.category,
|
|
27
|
-
};
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
function createConfigurationError() {
|
|
31
|
-
const error = new Error('onboarding_store_unavailable');
|
|
32
|
-
error.code = 'onboarding_store_unavailable';
|
|
33
|
-
error.status = 500;
|
|
34
|
-
error.responseBody = {
|
|
35
|
-
error: error.code,
|
|
36
|
-
message: 'onboarding activation requires a configured metadata store',
|
|
37
|
-
};
|
|
38
|
-
return error;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
function createInvalidActivationRequestError(fieldId, message) {
|
|
42
|
-
const error = new Error(`invalid_onboarding_activation:${fieldId}`);
|
|
43
|
-
error.code = 'invalid_onboarding_activation';
|
|
44
|
-
error.status = 400;
|
|
45
|
-
error.responseBody = {
|
|
46
|
-
error: error.code,
|
|
47
|
-
message: 'dialog-first onboarding activation only accepts backend-issued identity flow inputs',
|
|
48
|
-
fieldErrors: [
|
|
49
|
-
{
|
|
50
|
-
fieldId,
|
|
51
|
-
message,
|
|
52
|
-
},
|
|
53
|
-
],
|
|
54
|
-
};
|
|
55
|
-
return error;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
function createActivatedResponse({ agent, appToken, created, bindingSource }) {
|
|
59
|
-
return {
|
|
60
|
-
status: 'activated',
|
|
61
|
-
created: created === true,
|
|
62
|
-
bindingSource: normalizeText(bindingSource, null),
|
|
63
|
-
agentId: normalizeText(agent?.agentId, null),
|
|
64
|
-
appToken: normalizeText(appToken, null),
|
|
65
|
-
};
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
function validateActivationInput(input = {}) {
|
|
69
|
-
const normalizedInput = input && typeof input === 'object' && !Array.isArray(input) ? input : {};
|
|
70
|
-
const blockedFields = [
|
|
71
|
-
['agentId', 'dialog-first activation must not receive a user-provided agentId'],
|
|
72
|
-
['code', 'dialog-first activation must not receive a user-provided code'],
|
|
73
|
-
['appToken', 'dialog-first activation must not receive a user-provided appToken in the request body'],
|
|
74
|
-
];
|
|
75
|
-
|
|
76
|
-
for (const [fieldId, message] of blockedFields) {
|
|
77
|
-
if (normalizeText(normalizedInput[fieldId], null)) {
|
|
78
|
-
throw createInvalidActivationRequestError(fieldId, message);
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
return {
|
|
83
|
-
displayName: normalizeText(normalizedInput.displayName, DEFAULT_ACTIVATION_DISPLAY_NAME),
|
|
84
|
-
};
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
function createActivatedAgent({ store, displayName }) {
|
|
88
|
-
return store.createAgent({
|
|
89
|
-
displayName,
|
|
90
|
-
publicIdentity: {
|
|
91
|
-
displayName,
|
|
92
|
-
status: 'pending',
|
|
93
|
-
},
|
|
94
|
-
});
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
export function createOnboardingService({ worldService, store = null } = {}) {
|
|
98
|
-
function assertStore() {
|
|
99
|
-
if (!store) throw createConfigurationError();
|
|
100
|
-
return store;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
return {
|
|
104
|
-
getInstallManifest() {
|
|
105
|
-
const recommendedWorlds = worldService.listWorlds().slice(0, 3).map((world) => projectRecommendedWorld(world));
|
|
106
|
-
return {
|
|
107
|
-
product: 'claworld',
|
|
108
|
-
mode: 'agent_install',
|
|
109
|
-
installer: {
|
|
110
|
-
command: CLAWORLD_INSTALLER_COMMAND,
|
|
111
|
-
packageName: CLAWORLD_INSTALLER_PACKAGE_NAME,
|
|
112
|
-
minHostVersion: CLAWORLD_OPENCLAW_MIN_HOST_VERSION,
|
|
113
|
-
canonicalFlow: 'installer_first',
|
|
114
|
-
lifecycle: {
|
|
115
|
-
install: CLAWORLD_INSTALLER_COMMAND,
|
|
116
|
-
doctor: CLAWORLD_DOCTOR_COMMAND,
|
|
117
|
-
update: CLAWORLD_UPDATE_COMMAND,
|
|
118
|
-
uninstall: CLAWORLD_UNINSTALL_COMMAND,
|
|
119
|
-
},
|
|
120
|
-
},
|
|
121
|
-
plugin: {
|
|
122
|
-
pluginId: DEFAULT_INSTALL_CHANNEL_ID,
|
|
123
|
-
packageName: CLAWORLD_INSTALLER_PACKAGE_NAME,
|
|
124
|
-
installMode: 'npm',
|
|
125
|
-
minHostVersion: CLAWORLD_OPENCLAW_MIN_HOST_VERSION,
|
|
126
|
-
},
|
|
127
|
-
setup: {
|
|
128
|
-
channelId: DEFAULT_INSTALL_CHANNEL_ID,
|
|
129
|
-
defaultAccountId: DEFAULT_INSTALL_ACCOUNT_ID,
|
|
130
|
-
defaultLocalAgentId: DEFAULT_INSTALL_LOCAL_AGENT_ID,
|
|
131
|
-
configPath: 'channels.claworld.accounts.<accountId>',
|
|
132
|
-
credentialField: 'appToken',
|
|
133
|
-
managedBy: 'host_agent_or_openclaw_runtime',
|
|
134
|
-
userInput: {
|
|
135
|
-
requiresCode: false,
|
|
136
|
-
requiresAgentId: false,
|
|
137
|
-
requiresToken: false,
|
|
138
|
-
},
|
|
139
|
-
},
|
|
140
|
-
compatibility: {
|
|
141
|
-
nativeOpenclaw: {
|
|
142
|
-
status: 'compatibility_only',
|
|
143
|
-
commands: [
|
|
144
|
-
'openclaw onboard',
|
|
145
|
-
'openclaw channels add claworld --app-token <token>',
|
|
146
|
-
],
|
|
147
|
-
},
|
|
148
|
-
},
|
|
149
|
-
activation: {
|
|
150
|
-
endpoint: '/v1/onboarding/activate',
|
|
151
|
-
method: 'POST',
|
|
152
|
-
requiresUserCode: false,
|
|
153
|
-
canonicalIdentityField: 'agentId',
|
|
154
|
-
credentialField: 'appToken',
|
|
155
|
-
responseFields: ['status', 'agentId', 'appToken'],
|
|
156
|
-
},
|
|
157
|
-
verification: {
|
|
158
|
-
statusRoute: '/plugins/claworld/status',
|
|
159
|
-
pairTool: 'claworld_pair_agent',
|
|
160
|
-
expectedBinding: 'runtime_bound_by_app_token',
|
|
161
|
-
},
|
|
162
|
-
steps: [
|
|
163
|
-
`run ${CLAWORLD_INSTALLER_COMMAND}`,
|
|
164
|
-
'installer validates OpenClaw availability and minimum host version',
|
|
165
|
-
'installer verifies or installs the claworld OpenClaw plugin package',
|
|
166
|
-
'installer writes or refreshes the managed claworld channel config and binds it to the local main agent by default',
|
|
167
|
-
'installer reloads or starts the runtime and verifies the managed channel shape without requiring backend activation',
|
|
168
|
-
'first-run readiness goes through claworld_pair_agent and then claworld_profile with action=update_identity',
|
|
169
|
-
'claworld_profile(action=update_identity) performs activation when needed and completes the public displayName#code identity',
|
|
170
|
-
`ongoing lifecycle uses ${CLAWORLD_UPDATE_COMMAND} for tracked package updates plus managed repair, then ${CLAWORLD_DOCTOR_COMMAND} for health confirmation`,
|
|
171
|
-
],
|
|
172
|
-
recommendedWorlds,
|
|
173
|
-
status: 'ready',
|
|
174
|
-
};
|
|
175
|
-
},
|
|
176
|
-
getFirstRunPlan({ worldId = null } = {}) {
|
|
177
|
-
const preferredWorld = worldId ? worldService.getWorld(worldId) : null;
|
|
178
|
-
const fallbackWorld = worldService.getWorld('dating-demo-world');
|
|
179
|
-
const selectedWorld = preferredWorld || fallbackWorld || worldService.getWorld(worldService.listWorldIds()[0]);
|
|
180
|
-
|
|
181
|
-
return {
|
|
182
|
-
selectedWorld: selectedWorld ? { worldId: selectedWorld.worldId, displayName: selectedWorld.displayName } : null,
|
|
183
|
-
actions: [
|
|
184
|
-
'install the claworld plugin and write the managed config shape',
|
|
185
|
-
'run claworld_pair_agent to confirm readiness after install',
|
|
186
|
-
'if public identity is pending, call claworld_profile with action=update_identity',
|
|
187
|
-
'claworld_profile(action=update_identity) activates the backend binding when needed and persists the returned appToken',
|
|
188
|
-
'collect required world profile fields',
|
|
189
|
-
'validate world membership eligibility',
|
|
190
|
-
'start the first A2A loop or deliver world content',
|
|
191
|
-
],
|
|
192
|
-
status: 'ready',
|
|
193
|
-
};
|
|
194
|
-
},
|
|
195
|
-
activateInstallation({ auth = null, input = {} } = {}) {
|
|
196
|
-
const activationInput = validateActivationInput(input);
|
|
197
|
-
assertStore();
|
|
198
|
-
|
|
199
|
-
if (auth?.ok) {
|
|
200
|
-
return createActivatedResponse({
|
|
201
|
-
agent: auth.agent,
|
|
202
|
-
appToken: auth.token,
|
|
203
|
-
created: false,
|
|
204
|
-
bindingSource: 'provided_app_token',
|
|
205
|
-
});
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
const createdAgent = createActivatedAgent({
|
|
209
|
-
store,
|
|
210
|
-
displayName: activationInput.displayName,
|
|
211
|
-
});
|
|
212
|
-
return createActivatedResponse({
|
|
213
|
-
agent: createdAgent,
|
|
214
|
-
appToken: createdAgent.bootstrapCredential?.token || null,
|
|
215
|
-
created: true,
|
|
216
|
-
bindingSource: 'created_agent_app_token',
|
|
217
|
-
});
|
|
218
|
-
},
|
|
219
|
-
};
|
|
220
|
-
}
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import { createSystemMessageOrchestrator } from './world-conversation-text.js';
|
|
2
|
-
|
|
3
|
-
export function createWorldConversationOrchestrator({
|
|
4
|
-
worldService,
|
|
5
|
-
systemMessages = createSystemMessageOrchestrator(),
|
|
6
|
-
} = {}) {
|
|
7
|
-
return {
|
|
8
|
-
previewConversation({ worldId, conversationKey = 'cnv_preview' } = {}) {
|
|
9
|
-
const world = worldService.requireWorld(worldId);
|
|
10
|
-
const openingPlan = systemMessages.planMessages({
|
|
11
|
-
conversationId: conversationKey,
|
|
12
|
-
trigger: 'conversation_started',
|
|
13
|
-
worldRules: world.conversationTemplate.worldRules,
|
|
14
|
-
});
|
|
15
|
-
const convergencePlan = [];
|
|
16
|
-
|
|
17
|
-
return {
|
|
18
|
-
worldId: world.worldId,
|
|
19
|
-
conversationTemplate: {
|
|
20
|
-
mode: world.conversationTemplate.mode,
|
|
21
|
-
},
|
|
22
|
-
openingPlan,
|
|
23
|
-
convergencePlan,
|
|
24
|
-
status: 'preview_ready',
|
|
25
|
-
};
|
|
26
|
-
},
|
|
27
|
-
};
|
|
28
|
-
}
|
|
@@ -1,142 +0,0 @@
|
|
|
1
|
-
function normalizeBoolean(value, fallback = false) {
|
|
2
|
-
if (typeof value === 'boolean') return value;
|
|
3
|
-
return fallback;
|
|
4
|
-
}
|
|
5
|
-
|
|
6
|
-
function normalizePositiveInteger(value, fallback = null) {
|
|
7
|
-
const normalized = Number(value);
|
|
8
|
-
if (!Number.isFinite(normalized) || normalized <= 0) return fallback;
|
|
9
|
-
return Math.floor(normalized);
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
async function maybeGenerateShareCard({
|
|
13
|
-
agentCardService,
|
|
14
|
-
agentId,
|
|
15
|
-
identityStatus,
|
|
16
|
-
generateShareCard = false,
|
|
17
|
-
expiresInSeconds = null,
|
|
18
|
-
forceRegenerate = true,
|
|
19
|
-
}) {
|
|
20
|
-
if (!generateShareCard) return undefined;
|
|
21
|
-
if (identityStatus?.ready !== true) {
|
|
22
|
-
return {
|
|
23
|
-
status: 'unavailable',
|
|
24
|
-
reason: 'public_identity_not_ready',
|
|
25
|
-
};
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
try {
|
|
29
|
-
return await agentCardService.renderCard({
|
|
30
|
-
agentId,
|
|
31
|
-
expiresInSeconds: normalizePositiveInteger(expiresInSeconds, null),
|
|
32
|
-
forceRegenerate: normalizeBoolean(forceRegenerate, true),
|
|
33
|
-
});
|
|
34
|
-
} catch (error) {
|
|
35
|
-
return {
|
|
36
|
-
status: 'unavailable',
|
|
37
|
-
reason: 'generation_failed',
|
|
38
|
-
message: error?.publicMessage || error?.message || 'share card generation failed',
|
|
39
|
-
};
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
export function createProfileService({
|
|
44
|
-
publicIdentityService,
|
|
45
|
-
agentCardService,
|
|
46
|
-
} = {}) {
|
|
47
|
-
if (!publicIdentityService) {
|
|
48
|
-
throw new Error('profile_service_requires_public_identity_service');
|
|
49
|
-
}
|
|
50
|
-
if (!agentCardService) {
|
|
51
|
-
throw new Error('profile_service_requires_agent_card_service');
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
return {
|
|
55
|
-
getPublicIdentityStatus(input = {}) {
|
|
56
|
-
return publicIdentityService.getPublicIdentityStatus(input);
|
|
57
|
-
},
|
|
58
|
-
|
|
59
|
-
updatePublicIdentity(input = {}) {
|
|
60
|
-
return publicIdentityService.updatePublicIdentity(input);
|
|
61
|
-
},
|
|
62
|
-
|
|
63
|
-
assertPublicIdentityReady(input = {}) {
|
|
64
|
-
return publicIdentityService.assertPublicIdentityReady(input);
|
|
65
|
-
},
|
|
66
|
-
|
|
67
|
-
async getProfile({
|
|
68
|
-
agentId,
|
|
69
|
-
generateShareCard = false,
|
|
70
|
-
expiresInSeconds = null,
|
|
71
|
-
forceRegenerate = true,
|
|
72
|
-
} = {}) {
|
|
73
|
-
const identityStatus = publicIdentityService.getPublicIdentityStatus({ agentId });
|
|
74
|
-
const shareCard = await maybeGenerateShareCard({
|
|
75
|
-
agentCardService,
|
|
76
|
-
agentId,
|
|
77
|
-
identityStatus,
|
|
78
|
-
generateShareCard,
|
|
79
|
-
expiresInSeconds,
|
|
80
|
-
forceRegenerate,
|
|
81
|
-
});
|
|
82
|
-
return shareCard === undefined
|
|
83
|
-
? identityStatus
|
|
84
|
-
: {
|
|
85
|
-
...identityStatus,
|
|
86
|
-
shareCard,
|
|
87
|
-
};
|
|
88
|
-
},
|
|
89
|
-
|
|
90
|
-
async updateProfileIdentity({
|
|
91
|
-
agentId,
|
|
92
|
-
displayName,
|
|
93
|
-
generateShareCard = true,
|
|
94
|
-
expiresInSeconds = null,
|
|
95
|
-
forceRegenerate = true,
|
|
96
|
-
} = {}) {
|
|
97
|
-
const identityStatus = await publicIdentityService.updatePublicIdentity({
|
|
98
|
-
agentId,
|
|
99
|
-
displayName,
|
|
100
|
-
});
|
|
101
|
-
const shareCard = await maybeGenerateShareCard({
|
|
102
|
-
agentCardService,
|
|
103
|
-
agentId,
|
|
104
|
-
identityStatus,
|
|
105
|
-
generateShareCard,
|
|
106
|
-
expiresInSeconds,
|
|
107
|
-
forceRegenerate,
|
|
108
|
-
});
|
|
109
|
-
return shareCard === undefined
|
|
110
|
-
? identityStatus
|
|
111
|
-
: {
|
|
112
|
-
...identityStatus,
|
|
113
|
-
shareCard,
|
|
114
|
-
};
|
|
115
|
-
},
|
|
116
|
-
|
|
117
|
-
async executeProfileAction({
|
|
118
|
-
action = 'view',
|
|
119
|
-
agentId,
|
|
120
|
-
displayName = null,
|
|
121
|
-
generateShareCard = false,
|
|
122
|
-
expiresInSeconds = null,
|
|
123
|
-
forceRegenerate = true,
|
|
124
|
-
} = {}) {
|
|
125
|
-
if (action === 'update_identity') {
|
|
126
|
-
return this.updateProfileIdentity({
|
|
127
|
-
agentId,
|
|
128
|
-
displayName,
|
|
129
|
-
generateShareCard,
|
|
130
|
-
expiresInSeconds,
|
|
131
|
-
forceRegenerate,
|
|
132
|
-
});
|
|
133
|
-
}
|
|
134
|
-
return this.getProfile({
|
|
135
|
-
agentId,
|
|
136
|
-
generateShareCard,
|
|
137
|
-
expiresInSeconds,
|
|
138
|
-
forceRegenerate,
|
|
139
|
-
});
|
|
140
|
-
},
|
|
141
|
-
};
|
|
142
|
-
}
|
|
@@ -1,160 +0,0 @@
|
|
|
1
|
-
import { resolveAuthenticatedAgentId } from '../../lib/http-auth.js';
|
|
2
|
-
|
|
3
|
-
function normalizeBoolean(value, fallback = false) {
|
|
4
|
-
if (typeof value === 'boolean') return value;
|
|
5
|
-
if (typeof value === 'string') {
|
|
6
|
-
const normalized = value.trim().toLowerCase();
|
|
7
|
-
if (normalized === 'true') return true;
|
|
8
|
-
if (normalized === 'false') return false;
|
|
9
|
-
}
|
|
10
|
-
return fallback;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
function normalizePositiveInteger(value, fallback = null) {
|
|
14
|
-
const normalized = Number(value);
|
|
15
|
-
if (!Number.isFinite(normalized) || normalized <= 0) return fallback;
|
|
16
|
-
return Math.floor(normalized);
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
function buildAbsoluteUrl(req, publicPath) {
|
|
20
|
-
return `${req.protocol}://${req.get('host')}${publicPath}`;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
function normalizeShareCard(req, shareCard = undefined) {
|
|
24
|
-
if (shareCard === undefined) return undefined;
|
|
25
|
-
if (!shareCard || typeof shareCard !== 'object') return shareCard;
|
|
26
|
-
|
|
27
|
-
const card = shareCard.card && typeof shareCard.card === 'object' ? shareCard.card : null;
|
|
28
|
-
if (!card) return shareCard;
|
|
29
|
-
|
|
30
|
-
const imageUrl = card.imageUrl || (card.publicPath ? buildAbsoluteUrl(req, card.publicPath) : null);
|
|
31
|
-
const downloadUrl = card.downloadUrl || imageUrl;
|
|
32
|
-
if (!imageUrl && !downloadUrl) return shareCard;
|
|
33
|
-
return {
|
|
34
|
-
...shareCard,
|
|
35
|
-
card: {
|
|
36
|
-
...card,
|
|
37
|
-
...(imageUrl ? { imageUrl } : {}),
|
|
38
|
-
...(downloadUrl ? { downloadUrl } : {}),
|
|
39
|
-
},
|
|
40
|
-
};
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
function sendProfileError(res, error) {
|
|
44
|
-
const status = Number.isInteger(error?.status) ? error.status : 500;
|
|
45
|
-
if (error?.responseBody && typeof error.responseBody === 'object') {
|
|
46
|
-
return res.status(status).json(error.responseBody);
|
|
47
|
-
}
|
|
48
|
-
const code = typeof error?.code === 'string' ? error.code : 'internal_error';
|
|
49
|
-
return res.status(status).json({ error: code, message: error?.message || code });
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
function sendMissingAgentIdentity(res) {
|
|
53
|
-
return res.status(401).json({
|
|
54
|
-
error: 'not_authenticated',
|
|
55
|
-
reason: 'agent_identity_required',
|
|
56
|
-
});
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
export function registerPublicIdentityRoutes(app, { publicIdentityService, store }) {
|
|
60
|
-
app.get('/v1/profile', async (req, res) => {
|
|
61
|
-
const authAgent = resolveAuthenticatedAgentId({
|
|
62
|
-
store,
|
|
63
|
-
req,
|
|
64
|
-
providedAgentId: req.query.agentId,
|
|
65
|
-
fieldName: 'agentId',
|
|
66
|
-
});
|
|
67
|
-
if (!authAgent.ok) return res.status(authAgent.status).json(authAgent.body);
|
|
68
|
-
if (!authAgent.agentId) return sendMissingAgentIdentity(res);
|
|
69
|
-
|
|
70
|
-
try {
|
|
71
|
-
const result = await publicIdentityService.getProfile({
|
|
72
|
-
agentId: authAgent.agentId,
|
|
73
|
-
generateShareCard: normalizeBoolean(req.query.generateShareCard, false),
|
|
74
|
-
expiresInSeconds: normalizePositiveInteger(req.query.expiresInSeconds, null),
|
|
75
|
-
forceRegenerate: normalizeBoolean(req.query.forceRegenerate, true),
|
|
76
|
-
});
|
|
77
|
-
return res.json({
|
|
78
|
-
...result,
|
|
79
|
-
...(Object.prototype.hasOwnProperty.call(result, 'shareCard')
|
|
80
|
-
? { shareCard: normalizeShareCard(req, result.shareCard) }
|
|
81
|
-
: {}),
|
|
82
|
-
});
|
|
83
|
-
} catch (error) {
|
|
84
|
-
return sendProfileError(res, error);
|
|
85
|
-
}
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
app.post('/v1/profile', async (req, res) => {
|
|
89
|
-
const authAgent = resolveAuthenticatedAgentId({
|
|
90
|
-
store,
|
|
91
|
-
req,
|
|
92
|
-
providedAgentId: req.body?.agentId,
|
|
93
|
-
fieldName: 'agentId',
|
|
94
|
-
});
|
|
95
|
-
if (!authAgent.ok) return res.status(authAgent.status).json(authAgent.body);
|
|
96
|
-
if (!authAgent.agentId) return sendMissingAgentIdentity(res);
|
|
97
|
-
|
|
98
|
-
try {
|
|
99
|
-
const action = String(req.body?.action || '').trim() || (req.body?.displayName ? 'update_identity' : 'view');
|
|
100
|
-
const result = await publicIdentityService.executeProfileAction({
|
|
101
|
-
action,
|
|
102
|
-
agentId: authAgent.agentId,
|
|
103
|
-
displayName: req.body?.displayName,
|
|
104
|
-
generateShareCard: normalizeBoolean(req.body?.generateShareCard, action === 'update_identity'),
|
|
105
|
-
expiresInSeconds: normalizePositiveInteger(req.body?.expiresInSeconds, null),
|
|
106
|
-
forceRegenerate: normalizeBoolean(req.body?.forceRegenerate, true),
|
|
107
|
-
});
|
|
108
|
-
return res.json({
|
|
109
|
-
action,
|
|
110
|
-
...result,
|
|
111
|
-
...(Object.prototype.hasOwnProperty.call(result, 'shareCard')
|
|
112
|
-
? { shareCard: normalizeShareCard(req, result.shareCard) }
|
|
113
|
-
: {}),
|
|
114
|
-
});
|
|
115
|
-
} catch (error) {
|
|
116
|
-
return sendProfileError(res, error);
|
|
117
|
-
}
|
|
118
|
-
});
|
|
119
|
-
|
|
120
|
-
app.get('/v1/profile/public-identity', (req, res) => {
|
|
121
|
-
const authAgent = resolveAuthenticatedAgentId({
|
|
122
|
-
store,
|
|
123
|
-
req,
|
|
124
|
-
providedAgentId: req.query.agentId,
|
|
125
|
-
fieldName: 'agentId',
|
|
126
|
-
});
|
|
127
|
-
if (!authAgent.ok) return res.status(authAgent.status).json(authAgent.body);
|
|
128
|
-
if (!authAgent.agentId) return sendMissingAgentIdentity(res);
|
|
129
|
-
|
|
130
|
-
try {
|
|
131
|
-
const result = publicIdentityService.getPublicIdentityStatus({
|
|
132
|
-
agentId: authAgent.agentId,
|
|
133
|
-
});
|
|
134
|
-
return res.json(result);
|
|
135
|
-
} catch (error) {
|
|
136
|
-
return sendProfileError(res, error);
|
|
137
|
-
}
|
|
138
|
-
});
|
|
139
|
-
|
|
140
|
-
app.put('/v1/profile/public-identity', async (req, res) => {
|
|
141
|
-
const authAgent = resolveAuthenticatedAgentId({
|
|
142
|
-
store,
|
|
143
|
-
req,
|
|
144
|
-
providedAgentId: req.body?.agentId,
|
|
145
|
-
fieldName: 'agentId',
|
|
146
|
-
});
|
|
147
|
-
if (!authAgent.ok) return res.status(authAgent.status).json(authAgent.body);
|
|
148
|
-
if (!authAgent.agentId) return sendMissingAgentIdentity(res);
|
|
149
|
-
|
|
150
|
-
try {
|
|
151
|
-
const result = await publicIdentityService.updatePublicIdentity({
|
|
152
|
-
agentId: authAgent.agentId,
|
|
153
|
-
displayName: req.body?.displayName,
|
|
154
|
-
});
|
|
155
|
-
return res.json(result);
|
|
156
|
-
} catch (error) {
|
|
157
|
-
return sendProfileError(res, error);
|
|
158
|
-
}
|
|
159
|
-
});
|
|
160
|
-
}
|