@things-factory/figure-service 10.1.40 → 10.1.42

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/figure-service",
3
- "version": "10.1.40",
3
+ "version": "10.1.42",
4
4
  "publishConfig": {
5
5
  "access": "public",
6
6
  "@things-factory:registry": "https://registry.npmjs.org"
@@ -23,7 +23,7 @@
23
23
  "migration:create": "node ../../node_modules/typeorm/cli.js migration:create ./server/migrations/migration"
24
24
  },
25
25
  "dependencies": {
26
- "@hatiolab/figure-model": "^0.1.40",
26
+ "@hatiolab/figure-model": "^0.1.42",
27
27
  "@operato/typeorm-history": "^10.0.0",
28
28
  "@things-factory/ai-client-base": "^10.1.39",
29
29
  "@things-factory/auth-base": "^10.1.40",
@@ -33,5 +33,5 @@
33
33
  "graphql-upload": "^15.0.2",
34
34
  "koa-router": "^7.4.0"
35
35
  },
36
- "gitHead": "51c5d804c14ad8fcc6d4707e6ef80c9deede2766"
36
+ "gitHead": "982aa01403b979c4e348fd207a3fb4d1a7b5f521"
37
37
  }
@@ -120,8 +120,13 @@ describe('release gate — the base box', () => {
120
120
 
121
121
  expect(finding?.message).toMatch(/mm/)
122
122
  expect(finding?.why).toBeTruthy()
123
- /* 화면의 칸 이름으로 부른다 — 저작자는 `base.y` 를 본 적이 없고 Y 라고 적힌 칸을 본다. */
124
- expect(finding?.how).toMatch(/기준 상자의 Y/)
123
+ /*
124
+ 화면의 칸 이름으로 부른다 — 저작자는 `base.y` 를 본 적이 없고 Y 라고 적힌 칸을 본다. 이 부품은 바닥 아래로
125
+ 넘었고, 기준 상자의 밑면은 Y 0 에 고정이라 상자 크기로는 닿지 않는다 — 고칠 길은 부품을 올리는 것뿐이다
126
+ (figure-model 0.1.39, ADR-0065).
127
+ */
128
+ expect(finding?.how).toMatch(/Y 로 \d+(\.\d+)?mm 올리세요/)
129
+ expect(finding?.how).not.toMatch(/기준 상자의 Y 를 \d+/)
125
130
  })
126
131
 
127
132
  it('carries them for the placement face too', () => {
@@ -128,3 +128,13 @@ describe('inspectFigureDraft — the verdict while editing', () => {
128
128
  expect(declaration).toContain('category: "figure", privilege: "query"')
129
129
  })
130
130
  })
131
+
132
+ describe('format — which modeller a screen opens', () => {
133
+ it('reads the format off the stored source; a source it cannot identify has none', () => {
134
+ const query = new FigureQuery()
135
+ expect(query.format({ source: sound() } as any)).toBe('v3')
136
+ expect(query.format({ source: JSON.stringify({ version: 2, parts: [] }) } as any)).toBe('v2')
137
+ expect(query.format({ source: 'not json' } as any)).toBeNull()
138
+ expect(query.format({} as any)).toBeNull()
139
+ })
140
+ })
@@ -1,5 +1,5 @@
1
1
  import { In } from 'typeorm'
2
- import { Args, Arg, Ctx, Directive, Query, Resolver, UseMiddleware } from 'type-graphql'
2
+ import { Args, Arg, Ctx, Directive, FieldResolver, Query, Resolver, Root, UseMiddleware } from 'type-graphql'
3
3
  import { GraphQLJSON } from 'graphql-scalars'
4
4
  import { compile } from '@hatiolab/figure-model'
5
5
 
@@ -14,12 +14,29 @@ import {
14
14
 
15
15
  import { Figure } from './figure.js'
16
16
  import { FigureHistory } from './figure-history.js'
17
- import { consumablePayloadOf, inspectAnySource } from './figure-format.js'
17
+ import { consumablePayloadOf, formatOf, inspectAnySource } from './figure-format.js'
18
18
  import { FigureInspection, FigureList } from './figure-type.js'
19
19
 
20
20
  @Resolver(Figure)
21
21
  @UseMiddleware(SpeakRefusals)
22
22
  export class FigureQuery {
23
+ /**
24
+ * Which format the stored source is in — so a screen opens the modeller that can edit it.
25
+ *
26
+ * The catalogue sent every figure to the V2 modeller. A converted figure there fails to open, and the V3 modeller
27
+ * could only be reached by typing its address (2026-09-24). The row does not say; the source does (`formatOf`).
28
+ * A source the server cannot identify has no format rather than a guessed one.
29
+ */
30
+ @FieldResolver(type => String, { nullable: true, description: "The format of the stored source: 'v2' or 'v3'." })
31
+ format(@Root() figure: Figure): string | null {
32
+ if (!figure.source) return null
33
+ try {
34
+ return formatOf(figure.source)
35
+ } catch {
36
+ return null
37
+ }
38
+ }
39
+
23
40
  @Directive('@privilege(category: "figure", privilege: "query", domainOwnerGranted: true)')
24
41
  @Query(returns => Figure, { nullable: true, description: 'Finds a single figure by its ID.' })
25
42
  async figure(@Arg('id') id: string, @Ctx() context: ResolverContext): Promise<Figure> {