@things-factory/board-import 10.1.29 → 10.1.31
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@things-factory/board-import",
|
|
3
|
-
"version": "10.1.
|
|
3
|
+
"version": "10.1.31",
|
|
4
4
|
"main": "dist-server/index.js",
|
|
5
5
|
"things-factory": true,
|
|
6
6
|
"author": "heartyoh",
|
|
@@ -23,13 +23,13 @@
|
|
|
23
23
|
},
|
|
24
24
|
"dependencies": {
|
|
25
25
|
"@operato/graphql": "^10.0.0",
|
|
26
|
-
"@things-factory/ai-client-base": "^10.1.
|
|
27
|
-
"@things-factory/attachment-base": "^10.1.
|
|
28
|
-
"@things-factory/auth-base": "^10.1.
|
|
29
|
-
"@things-factory/board-service": "^10.1.
|
|
26
|
+
"@things-factory/ai-client-base": "^10.1.31",
|
|
27
|
+
"@things-factory/attachment-base": "^10.1.31",
|
|
28
|
+
"@things-factory/auth-base": "^10.1.31",
|
|
29
|
+
"@things-factory/board-service": "^10.1.31",
|
|
30
30
|
"@things-factory/env": "^10.1.20",
|
|
31
|
-
"@things-factory/shell": "^10.1.
|
|
31
|
+
"@things-factory/shell": "^10.1.31",
|
|
32
32
|
"dxf-parser": "^1.1.2"
|
|
33
33
|
},
|
|
34
|
-
"gitHead": "
|
|
34
|
+
"gitHead": "5213e6f9913b40ea2618a2111d9884b792dbaa01"
|
|
35
35
|
}
|
|
@@ -42,6 +42,12 @@ const ARGS: Record<keyof typeof IMPORT_TOOL_PRIVILEGE, any> = {
|
|
|
42
42
|
getImportSession: { sessionId: 's1' },
|
|
43
43
|
materializeImportSession: { sessionId: 's1', name: 'New' }
|
|
44
44
|
}
|
|
45
|
+
/** 도구가 지나는 문 — 등록기의 `doors`, 그리고 아래 「표가 문과 같은가」가 읽는 필드 이름. */
|
|
46
|
+
const DOOR: Record<keyof typeof IMPORT_TOOL_PRIVILEGE, string> = {
|
|
47
|
+
importBoardAsync: 'Mutation.importBoardAsync',
|
|
48
|
+
getImportSession: 'Query.importSession',
|
|
49
|
+
materializeImportSession: 'Mutation.materializeImportSession'
|
|
50
|
+
}
|
|
45
51
|
const EFFECT: Record<keyof typeof IMPORT_TOOL_PRIVILEGE, jest.Mock> = {
|
|
46
52
|
importBoardAsync: mockStartImportJobAsync,
|
|
47
53
|
getImportSession: mockFetchImportSession,
|
|
@@ -73,22 +79,24 @@ describe.each(Object.keys(IMPORT_TOOL_PRIVILEGE) as (keyof typeof IMPORT_TOOL_PR
|
|
|
73
79
|
expect(EFFECT[tool]).toHaveBeenCalled()
|
|
74
80
|
})
|
|
75
81
|
|
|
76
|
-
|
|
82
|
+
/*
|
|
83
|
+
* 무엇을 **내보낼지**는 2026-09-18 부터 문이 정한다(ADR-0071 결정 2). 명세가 권한을 베껴 적는 대신
|
|
84
|
+
* 닿는 문을 적고, 관문이 그 필드의 지시자를 AUTH 의 표에서 읽는다. 여기 적힌 문 이름이 틀리면 그
|
|
85
|
+
* 도구는 어느 대화에도 안 나간다 — 조용히.
|
|
86
|
+
*/
|
|
87
|
+
test('names the door it reaches, so the gate can ask that door what it requires', () => {
|
|
77
88
|
const spec: any = findToolSpec(tool)
|
|
78
|
-
expect(spec.
|
|
89
|
+
expect(spec.doors).toEqual([DOOR[tool]])
|
|
90
|
+
expect(spec.privilege).toBeUndefined()
|
|
79
91
|
})
|
|
80
92
|
})
|
|
81
93
|
|
|
82
94
|
test('the table says what the GraphQL doors say', () => {
|
|
83
95
|
const resolver = readFileSync(join(__dirname, 'import-session', 'import-session-resolver.ts'), 'utf8')
|
|
84
|
-
const DOOR: Record<keyof typeof IMPORT_TOOL_PRIVILEGE, string> = {
|
|
85
|
-
importBoardAsync: 'importBoardAsync',
|
|
86
|
-
getImportSession: 'importSession',
|
|
87
|
-
materializeImportSession: 'materializeImportSession'
|
|
88
|
-
}
|
|
89
96
|
for (const [tool, door] of Object.entries(DOOR) as [keyof typeof IMPORT_TOOL_PRIVILEGE, string][]) {
|
|
97
|
+
const field = door.split('.')[1]
|
|
90
98
|
const m = resolver.match(
|
|
91
|
-
new RegExp(`@Directive\\('@privilege\\(category: "([^"]+)", privilege: "([^"]+)"\\)'\\)\\s*async ${
|
|
99
|
+
new RegExp(`@Directive\\('@privilege\\(category: "([^"]+)", privilege: "([^"]+)"\\)'\\)\\s*async ${field}\\(`)
|
|
92
100
|
)
|
|
93
101
|
expect(m).not.toBeNull()
|
|
94
102
|
expect({ category: m![1], privilege: m![2] }).toEqual(IMPORT_TOOL_PRIVILEGE[tool])
|
|
@@ -84,9 +84,13 @@ function requireDomainContext(state: any): { domain: any; user: any } {
|
|
|
84
84
|
* `ai-assistant:mutation` — could create a Board through it.
|
|
85
85
|
*
|
|
86
86
|
* The check lives in the builder rather than in whichever chat door dispatches the tool: there is
|
|
87
|
-
* more than one such door, and the effect has to be guarded wherever it is reached from.
|
|
88
|
-
*
|
|
89
|
-
*
|
|
87
|
+
* more than one such door, and the effect has to be guarded wherever it is reached from.
|
|
88
|
+
*
|
|
89
|
+
* Whether the tool is **offered** at all is a separate question, and since 2026-09-18 the spec does
|
|
90
|
+
* not answer it with a copy of this object (ADR-0071 decision 2). The spec names the GraphQL doors
|
|
91
|
+
* it reaches and the gate resolves each one against that field's own `@privilege` — the same
|
|
92
|
+
* declarations this constant mirrors (`import-session-resolver.ts`). This constant stays because it
|
|
93
|
+
* guards the **effect**, which is reached from more places than the offering.
|
|
90
94
|
*/
|
|
91
95
|
export const IMPORT_TOOL_PRIVILEGE = {
|
|
92
96
|
importBoardAsync: { category: 'board-import', privilege: 'mutation' },
|
|
@@ -134,6 +138,8 @@ const importToolsCategory: ToolCategory = {
|
|
|
134
138
|
{
|
|
135
139
|
kind: 'read',
|
|
136
140
|
name: 'listImportAdapters',
|
|
141
|
+
/* 등록된 어댑터를 그 자리에서 셀 뿐이다 — 저장소에 닿지 않으므로 지나는 문이 없다. */
|
|
142
|
+
doors: [],
|
|
137
143
|
description:
|
|
138
144
|
'등록된 도면 import 어댑터 (DXF / Image / 향후 IFC, glTF 등) 의 능력 조회. ' +
|
|
139
145
|
'사용자가 어떤 형식 import 가 가능한지 묻거나, LLM 이 적절한 어댑터 선택을 inspect 할 때 사용.',
|
|
@@ -149,7 +155,7 @@ const importToolsCategory: ToolCategory = {
|
|
|
149
155
|
{
|
|
150
156
|
kind: 'external',
|
|
151
157
|
name: 'importBoardAsync',
|
|
152
|
-
|
|
158
|
+
doors: ['Mutation.importBoardAsync'],
|
|
153
159
|
description:
|
|
154
160
|
'Attachment(도면/조감도/사진) 을 비동기로 보드 모델로 변환 시작. 즉시 ImportSession 을 ' +
|
|
155
161
|
'반환하고 백그라운드에서 진행. status 가 completed 가 될 때까지 getImportSession 으로 ' +
|
|
@@ -201,7 +207,7 @@ const importToolsCategory: ToolCategory = {
|
|
|
201
207
|
{
|
|
202
208
|
kind: 'read',
|
|
203
209
|
name: 'getImportSession',
|
|
204
|
-
|
|
210
|
+
doors: ['Query.importSession'],
|
|
205
211
|
description:
|
|
206
212
|
'ImportSession 의 진행/결과 조회. status 가 queued/parsing/mapping/assembling/binding 인 ' +
|
|
207
213
|
'동안은 progress 와 message 를 반환, completed 면 result.boardModel 까지 포함. failed 면 ' +
|
|
@@ -237,7 +243,7 @@ const importToolsCategory: ToolCategory = {
|
|
|
237
243
|
{
|
|
238
244
|
kind: 'external',
|
|
239
245
|
name: 'materializeImportSession',
|
|
240
|
-
|
|
246
|
+
doors: ['Mutation.materializeImportSession'],
|
|
241
247
|
description:
|
|
242
248
|
'완료된 ImportSession 의 결과 boardModel 을 새 Board entity 로 영속화. status 가 ' +
|
|
243
249
|
'completed 인 세션만 처리. 결과 Board 는 state="draft" 로 생성되므로 사용자가 검수 후 ' +
|