@realsee/vr-cli 0.1.4 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +46 -29
- package/agent-assets/AGENTS.md +8 -5
- package/dist/cli.mjs +5 -5
- package/package.json +1 -1
- package/skills/realsee-vr-app/SKILL.md +1 -1
- package/skills/realsee-vr-app/references/dnalogel-openapi-recipes.md +90 -26
- package/skills/realsee-vr-app/references/five-runtime.md +2 -2
- package/skills/realsee-vr-app/scripts/verify-project.mjs +194 -13
- package/templates/base/.env.example +4 -2
- package/templates/base/.gitignore.template +2 -0
- package/templates/base/.prettierignore +2 -0
- package/templates/base/README.md +35 -8
- package/templates/base/deploy.json +11 -0
- package/templates/base/eslint.config.mjs +2 -0
- package/templates/base/package-lock.json +11 -0
- package/templates/base/package.json +6 -1
- package/templates/base/scripts/package-vibe-release.mjs +569 -0
- package/templates/base/scripts/pairing.mjs +564 -0
- package/templates/base/scripts/pairing.test.mjs +227 -0
- package/templates/base/scripts/project-identity.mjs +160 -0
- package/templates/base/scripts/project-identity.test.mjs +119 -0
- package/templates/base/scripts/setup-config.mjs +252 -0
- package/templates/base/scripts/setup-config.test.mjs +123 -0
- package/templates/base/scripts/setup.mjs +203 -0
- package/templates/base/server/app.ts +3 -1
- package/templates/base/server/config.ts +12 -1
- package/templates/base/server/index.ts +5 -1
- package/templates/base/server/types.ts +2 -1
- package/templates/base/server/work-route.ts +51 -32
- package/templates/base/server/work-service.ts +2 -2
- package/templates/base/src/vr/work/WorkSource.ts +13 -9
|
@@ -5,6 +5,7 @@ const RESOURCE_CODE_PATTERN = '^[A-Za-z0-9_-]{1,128}$'
|
|
|
5
5
|
|
|
6
6
|
export interface WorkRoutesOptions {
|
|
7
7
|
readonly workService: WorkService
|
|
8
|
+
readonly defaultResourceCode: string | undefined
|
|
8
9
|
}
|
|
9
10
|
|
|
10
11
|
interface WorkRouteParams {
|
|
@@ -23,9 +24,56 @@ const upstreamStatusCode = (error: unknown): number => {
|
|
|
23
24
|
|
|
24
25
|
export function workRoutes(
|
|
25
26
|
app: FastifyInstance,
|
|
26
|
-
{ workService }: WorkRoutesOptions,
|
|
27
|
+
{ workService, defaultResourceCode }: WorkRoutesOptions,
|
|
27
28
|
done: (error?: Error) => void,
|
|
28
29
|
): void {
|
|
30
|
+
const getWork = async (
|
|
31
|
+
request: FastifyRequest,
|
|
32
|
+
reply: FastifyReply,
|
|
33
|
+
resourceCode: string,
|
|
34
|
+
): Promise<WorkEnvelope | FastifyReply> => {
|
|
35
|
+
const requestAbort = new AbortController()
|
|
36
|
+
const abortDisconnectedRequest = (): void => {
|
|
37
|
+
if (request.raw.aborted || !request.raw.complete) requestAbort.abort()
|
|
38
|
+
}
|
|
39
|
+
request.raw.once('close', abortDisconnectedRequest)
|
|
40
|
+
|
|
41
|
+
try {
|
|
42
|
+
return await workService.getWorkByResourceCode(resourceCode, {
|
|
43
|
+
signal: requestAbort.signal,
|
|
44
|
+
})
|
|
45
|
+
} catch (error) {
|
|
46
|
+
const statusCode = upstreamStatusCode(error)
|
|
47
|
+
request.log.error({ err: error }, 'Work BFF request failed')
|
|
48
|
+
return reply.code(statusCode).send({
|
|
49
|
+
error:
|
|
50
|
+
statusCode === 404
|
|
51
|
+
? 'WORK_NOT_FOUND'
|
|
52
|
+
: statusCode === 504
|
|
53
|
+
? 'WORK_UPSTREAM_TIMEOUT'
|
|
54
|
+
: 'WORK_UPSTREAM_FAILED',
|
|
55
|
+
requestId: request.id,
|
|
56
|
+
})
|
|
57
|
+
} finally {
|
|
58
|
+
request.raw.off('close', abortDisconnectedRequest)
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
app.get(
|
|
63
|
+
'/api/work',
|
|
64
|
+
async (request, reply): Promise<WorkEnvelope | FastifyReply> => {
|
|
65
|
+
if (!defaultResourceCode) {
|
|
66
|
+
return reply.code(400).send({
|
|
67
|
+
error: 'RESOURCE_CODE_REQUIRED',
|
|
68
|
+
message:
|
|
69
|
+
'Provide resourceCode at /api/work/{resourceCode} or configure the optional REALSEE_DEFAULT_RESOURCE_CODE fallback.',
|
|
70
|
+
requestId: request.id,
|
|
71
|
+
})
|
|
72
|
+
}
|
|
73
|
+
return getWork(request, reply, defaultResourceCode)
|
|
74
|
+
},
|
|
75
|
+
)
|
|
76
|
+
|
|
29
77
|
app.get(
|
|
30
78
|
'/api/work/:resourceCode',
|
|
31
79
|
{
|
|
@@ -43,37 +91,8 @@ export function workRoutes(
|
|
|
43
91
|
async (
|
|
44
92
|
request: FastifyRequest<{ Params: WorkRouteParams }>,
|
|
45
93
|
reply: FastifyReply,
|
|
46
|
-
): Promise<WorkEnvelope | FastifyReply> =>
|
|
47
|
-
|
|
48
|
-
const requestAbort = new AbortController()
|
|
49
|
-
const abortDisconnectedRequest = (): void => {
|
|
50
|
-
if (request.raw.aborted || !request.raw.complete) requestAbort.abort()
|
|
51
|
-
}
|
|
52
|
-
request.raw.once('close', abortDisconnectedRequest)
|
|
53
|
-
|
|
54
|
-
try {
|
|
55
|
-
return await workService.getWorkByResourceCode(resourceCode, {
|
|
56
|
-
signal: requestAbort.signal,
|
|
57
|
-
})
|
|
58
|
-
} catch (error) {
|
|
59
|
-
const statusCode = upstreamStatusCode(error)
|
|
60
|
-
request.log.error(
|
|
61
|
-
{ err: error, resourceCode },
|
|
62
|
-
'Work BFF request failed',
|
|
63
|
-
)
|
|
64
|
-
return reply.code(statusCode).send({
|
|
65
|
-
error:
|
|
66
|
-
statusCode === 404
|
|
67
|
-
? 'WORK_NOT_FOUND'
|
|
68
|
-
: statusCode === 504
|
|
69
|
-
? 'WORK_UPSTREAM_TIMEOUT'
|
|
70
|
-
: 'WORK_UPSTREAM_FAILED',
|
|
71
|
-
requestId: request.id,
|
|
72
|
-
})
|
|
73
|
-
} finally {
|
|
74
|
-
request.raw.off('close', abortDisconnectedRequest)
|
|
75
|
-
}
|
|
76
|
-
},
|
|
94
|
+
): Promise<WorkEnvelope | FastifyReply> =>
|
|
95
|
+
getWork(request, reply, request.params.resourceCode),
|
|
77
96
|
)
|
|
78
97
|
|
|
79
98
|
done()
|
|
@@ -27,8 +27,8 @@ export function createWorkService({
|
|
|
27
27
|
.catch((error: unknown) => {
|
|
28
28
|
if (!signal?.aborted) {
|
|
29
29
|
console.warn(
|
|
30
|
-
|
|
31
|
-
error,
|
|
30
|
+
'所选空间的平面图 capability 不可用,继续返回基础 Work。',
|
|
31
|
+
error instanceof Error ? error.name : 'UnknownError',
|
|
32
32
|
)
|
|
33
33
|
}
|
|
34
34
|
return undefined
|
|
@@ -177,7 +177,9 @@ const asExplicitPanoTagList = (value: unknown): Tags['tagList'] | undefined => {
|
|
|
177
177
|
|
|
178
178
|
export function resourceCodeFromPathname(pathname: string) {
|
|
179
179
|
const segments = pathname.split('/').filter(Boolean)
|
|
180
|
-
if (segments.length
|
|
180
|
+
if (segments.length === 0) return undefined
|
|
181
|
+
if (segments.length !== 1)
|
|
182
|
+
throw new Error('访问路径必须为 / 或 /{resourceCode}。')
|
|
181
183
|
const [encodedResourceCode = ''] = segments
|
|
182
184
|
|
|
183
185
|
let resourceCode: string
|
|
@@ -199,13 +201,13 @@ export class RouteWorkSource implements WorkSource {
|
|
|
199
201
|
async load(signal?: AbortSignal): Promise<WorkPayload> {
|
|
200
202
|
const resourceCode = resourceCodeFromPathname(window.location.pathname)
|
|
201
203
|
// The generated Fastify BFF implements this contract; another language may replace it without changing the browser.
|
|
202
|
-
const
|
|
203
|
-
`/api/work/${encodeURIComponent(resourceCode)}
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
},
|
|
208
|
-
)
|
|
204
|
+
const workUrl = resourceCode
|
|
205
|
+
? `/api/work/${encodeURIComponent(resourceCode)}`
|
|
206
|
+
: '/api/work'
|
|
207
|
+
const response = await fetch(workUrl, {
|
|
208
|
+
signal,
|
|
209
|
+
headers: { Accept: 'application/json' },
|
|
210
|
+
})
|
|
209
211
|
if (!response.ok) throw new Error(`Work 请求失败:HTTP ${response.status}`)
|
|
210
212
|
|
|
211
213
|
const raw = (await response.json()) as unknown
|
|
@@ -221,7 +223,9 @@ export class RouteWorkSource implements WorkSource {
|
|
|
221
223
|
work.workCode,
|
|
222
224
|
work.work_code,
|
|
223
225
|
work.code,
|
|
224
|
-
) ??
|
|
226
|
+
) ??
|
|
227
|
+
resourceCode ??
|
|
228
|
+
'unknown-work'
|
|
225
229
|
const presetData = asRecord(envelope.presetData)
|
|
226
230
|
const panoTagList = asExplicitPanoTagList(presetData.panoTagList)
|
|
227
231
|
const modelFloorplan = asModelFloorplanServerData(
|