@things-factory/figure-service 10.1.178 → 10.1.180

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.
Files changed (82) hide show
  1. package/dist-server/index.d.ts +2 -0
  2. package/dist-server/index.js +6 -1
  3. package/dist-server/index.js.map +1 -1
  4. package/dist-server/routers/figure-mesh-router.js +4 -1
  5. package/dist-server/routers/figure-mesh-router.js.map +1 -1
  6. package/dist-server/routers/figure-thumbnail-router.js +3 -7
  7. package/dist-server/routers/figure-thumbnail-router.js.map +1 -1
  8. package/dist-server/service/figure/figure-categories.d.ts +10 -0
  9. package/dist-server/service/figure/figure-categories.js +53 -0
  10. package/dist-server/service/figure/figure-categories.js.map +1 -0
  11. package/dist-server/service/figure/figure-format.d.ts +18 -1
  12. package/dist-server/service/figure/figure-format.js +28 -1
  13. package/dist-server/service/figure/figure-format.js.map +1 -1
  14. package/dist-server/service/figure/figure-mutation.d.ts +8 -2
  15. package/dist-server/service/figure/figure-mutation.js +83 -34
  16. package/dist-server/service/figure/figure-mutation.js.map +1 -1
  17. package/dist-server/service/figure/figure-namespace-entity.d.ts +24 -0
  18. package/dist-server/service/figure/figure-namespace-entity.js +87 -0
  19. package/dist-server/service/figure/figure-namespace-entity.js.map +1 -0
  20. package/dist-server/service/figure/figure-namespace-resolver.d.ts +5 -8
  21. package/dist-server/service/figure/figure-namespace-resolver.js +52 -36
  22. package/dist-server/service/figure/figure-namespace-resolver.js.map +1 -1
  23. package/dist-server/service/figure/figure-namespace.d.ts +28 -28
  24. package/dist-server/service/figure/figure-namespace.js +105 -63
  25. package/dist-server/service/figure/figure-namespace.js.map +1 -1
  26. package/dist-server/service/figure/figure-package-export.js +4 -2
  27. package/dist-server/service/figure/figure-package-export.js.map +1 -1
  28. package/dist-server/service/figure/figure-public.d.ts +19 -0
  29. package/dist-server/service/figure/figure-public.js +54 -0
  30. package/dist-server/service/figure/figure-public.js.map +1 -0
  31. package/dist-server/service/figure/figure-query.d.ts +7 -0
  32. package/dist-server/service/figure/figure-query.js +59 -5
  33. package/dist-server/service/figure/figure-query.js.map +1 -1
  34. package/dist-server/service/figure/figure-rename.d.ts +25 -2
  35. package/dist-server/service/figure/figure-rename.js +21 -2
  36. package/dist-server/service/figure/figure-rename.js.map +1 -1
  37. package/dist-server/service/figure/figure-tools.js +1 -1
  38. package/dist-server/service/figure/figure-tools.js.map +1 -1
  39. package/dist-server/service/figure/figure-type.d.ts +1 -0
  40. package/dist-server/service/figure/figure-type.js +4 -0
  41. package/dist-server/service/figure/figure-type.js.map +1 -1
  42. package/dist-server/service/figure/figure.d.ts +1 -0
  43. package/dist-server/service/figure/figure.js +5 -0
  44. package/dist-server/service/figure/figure.js.map +1 -1
  45. package/dist-server/service/figure/index.d.ts +2 -1
  46. package/dist-server/service/figure/index.js +2 -1
  47. package/dist-server/service/figure/index.js.map +1 -1
  48. package/dist-server/service/index.d.ts +1 -1
  49. package/dist-server/tsconfig.tsbuildinfo +1 -1
  50. package/package.json +7 -7
  51. package/server/index.ts +2 -0
  52. package/server/routers/figure-mesh-router.ts +5 -1
  53. package/server/routers/figure-thumbnail-router.ts +3 -5
  54. package/server/service/figure/figure-categories.ts +50 -0
  55. package/server/service/figure/figure-category-db.test.ts +127 -0
  56. package/server/service/figure/figure-deprecation-db.test.ts +110 -6
  57. package/server/service/figure/figure-format.ts +43 -1
  58. package/server/service/figure/figure-mesh-db.test.ts +4 -2
  59. package/server/service/figure/figure-mutation.ts +79 -37
  60. package/server/service/figure/figure-namespace-db.test.ts +140 -74
  61. package/server/service/figure/figure-namespace-entity.ts +67 -0
  62. package/server/service/figure/figure-namespace-resolver.ts +39 -26
  63. package/server/service/figure/figure-namespace.ts +122 -81
  64. package/server/service/figure/figure-package-export.ts +6 -3
  65. package/server/service/figure/figure-proposal-db.test.ts +5 -3
  66. package/server/service/figure/figure-public-db.test.ts +180 -0
  67. package/server/service/figure/figure-public.ts +60 -0
  68. package/server/service/figure/figure-query.ts +48 -5
  69. package/server/service/figure/figure-release-check.test.ts +63 -0
  70. package/server/service/figure/figure-release-record-db.test.ts +7 -5
  71. package/server/service/figure/figure-rename-db.test.ts +50 -4
  72. package/server/service/figure/figure-rename.ts +37 -3
  73. package/server/service/figure/figure-tools.ts +1 -1
  74. package/server/service/figure/figure-type.ts +3 -0
  75. package/server/service/figure/figure.ts +8 -0
  76. package/server/service/figure/index.ts +2 -1
  77. package/translations/en.json +12 -3
  78. package/translations/es.json +12 -3
  79. package/translations/ja.json +12 -3
  80. package/translations/ko.json +12 -3
  81. package/translations/ms.json +12 -3
  82. package/translations/zh.json +12 -3
@@ -15,6 +15,8 @@ const figure_replaced_draft_js_1 = require("./figure-replaced-draft.js");
15
15
  const figure_revert_js_1 = require("./figure-revert.js");
16
16
  const figure_proposal_js_1 = require("./figure-proposal.js");
17
17
  const figure_mesh_store_js_1 = require("./figure-mesh-store.js");
18
+ const figure_public_js_1 = require("./figure-public.js");
19
+ const figure_categories_js_1 = require("./figure-categories.js");
18
20
  let FigureQuery = class FigureQuery {
19
21
  async figure(id, context) {
20
22
  const { domain } = context.state;
@@ -42,6 +44,25 @@ let FigureQuery = class FigureQuery {
42
44
  const [items, total] = await queryBuilder.getManyAndCount();
43
45
  return { items, total };
44
46
  }
47
+ /**
48
+ * Other domains' public figures (LV figure-server design G2): what this domain may read, package and draw besides its
49
+ * own and its parent's. The rows carry their domain, so a screen says whose each is. Their drafts are not opened.
50
+ */
51
+ async publicFigures(params, context) {
52
+ const { domain } = context.state;
53
+ const mine = [domain.id, domain.parentId].filter(Boolean);
54
+ const queryBuilder = (0, shell_1.getQueryBuilderFromListParams)({
55
+ repository: (0, shell_1.getRepository)(figure_js_1.Figure),
56
+ params,
57
+ alias: 'figure',
58
+ searchables: ['type', 'name', 'description', 'category', 'tags']
59
+ })
60
+ .leftJoinAndSelect('figure.domain', 'owner')
61
+ .andWhere('figure.public = :public', { public: true })
62
+ .andWhere('owner.id NOT IN (:...mine)', { mine });
63
+ const [items, total] = await queryBuilder.getManyAndCount();
64
+ return { items, total };
65
+ }
45
66
  /**
46
67
  * 등록된 타입 이름 목록.
47
68
  *
@@ -58,8 +79,11 @@ let FigureQuery = class FigureQuery {
58
79
  */
59
80
  async figureVersions(id, context) {
60
81
  const { domain } = context.state;
82
+ /* Its own, its parent's, or another domain's public figure (G2): releases are what a public figure shows. */
83
+ if (!(await (0, figure_public_js_1.readableFigure)(domain, id, { id: true, public: true, domain: { id: true } })))
84
+ return [];
61
85
  return await (0, shell_1.getRepository)(figure_history_js_1.FigureHistory).find({
62
- where: { domain: { id: (0, typeorm_1.In)([domain.id, domain.parentId].filter(Boolean)) }, originalId: id },
86
+ where: { originalId: id },
63
87
  relations: ['updater'],
64
88
  order: { version: 'DESC' },
65
89
  take: 10
@@ -88,8 +112,10 @@ let FigureQuery = class FigureQuery {
88
112
  }
89
113
  async figureReleased(id, context) {
90
114
  const { domain } = context.state;
115
+ if (!(await (0, figure_public_js_1.readableFigure)(domain, id, { id: true, public: true, domain: { id: true } })))
116
+ return null;
91
117
  return await (0, shell_1.getRepository)(figure_history_js_1.FigureHistory).findOne({
92
- where: { domain: { id: (0, typeorm_1.In)([domain.id, domain.parentId].filter(Boolean)) }, originalId: id },
118
+ where: { originalId: id },
93
119
  order: { version: 'DESC' }
94
120
  });
95
121
  }
@@ -124,7 +150,7 @@ let FigureQuery = class FigureQuery {
124
150
  .orderBy('history.version', 'DESC')
125
151
  .limit(1)
126
152
  .getOne();
127
- return (0, figure_format_js_1.inspectSource)(figure.source, released?.source, context.t, figure.type);
153
+ return (0, figure_format_js_1.inspectSource)(figure.source, released?.source, context.t, figure.type, figure.category);
128
154
  }
129
155
  /**
130
156
  * The same judgement for a source that has not been saved — what the modeller shows **while** the author edits.
@@ -150,7 +176,12 @@ let FigureQuery = class FigureQuery {
150
176
  .orderBy('history.version', 'DESC')
151
177
  .limit(1)
152
178
  .getOne();
153
- return (0, figure_format_js_1.inspectSource)(source, released?.source, context.t, figure.type);
179
+ return (0, figure_format_js_1.inspectSource)(source, released?.source, context.t, figure.type, figure.category);
180
+ }
181
+ /** The categories this server allows (G5), or null when a category is free text: the modeller offers them to choose from. */
182
+ async figureCategories() {
183
+ const codes = (0, figure_categories_js_1.figureCategories)();
184
+ return codes ? [...codes] : null;
154
185
  }
155
186
  async figureTypeNames(context) {
156
187
  const { domain } = context.state;
@@ -262,7 +293,9 @@ let FigureQuery = class FigureQuery {
262
293
  refuse(type, new shell_1.Refusal('figure-name-malformed', { type }, '{type} is not a full figure name of the form namespace/type.'));
263
294
  continue;
264
295
  }
265
- const found = (await releasedSourceOfName(domain.id, name)) ?? (domain.parentId ? await releasedSourceOfName(domain.parentId, name) : null);
296
+ const found = (await releasedSourceOfName(domain.id, name)) ??
297
+ (domain.parentId ? await releasedSourceOfName(domain.parentId, name) : null) ??
298
+ (await publicReleasedSourceOf(name));
266
299
  if (!found) {
267
300
  refuse(type, new shell_1.Refusal('figure-not-released', { type }, 'no release is published here.'));
268
301
  continue;
@@ -296,6 +329,15 @@ tslib_1.__decorate([
296
329
  tslib_1.__metadata("design:paramtypes", [shell_1.ListParam, Object]),
297
330
  tslib_1.__metadata("design:returntype", Promise)
298
331
  ], FigureQuery.prototype, "figures", null);
332
+ tslib_1.__decorate([
333
+ (0, type_graphql_1.Directive)('@privilege(category: "figure", privilege: "query", domainOwnerGranted: true)'),
334
+ (0, type_graphql_1.Query)(returns => figure_type_js_1.FigureList, { description: "Other domains' public figures. Read only: their releases, never their drafts." }),
335
+ tslib_1.__param(0, (0, type_graphql_1.Args)()),
336
+ tslib_1.__param(1, (0, type_graphql_1.Ctx)()),
337
+ tslib_1.__metadata("design:type", Function),
338
+ tslib_1.__metadata("design:paramtypes", [shell_1.ListParam, Object]),
339
+ tslib_1.__metadata("design:returntype", Promise)
340
+ ], FigureQuery.prototype, "publicFigures", null);
299
341
  tslib_1.__decorate([
300
342
  (0, type_graphql_1.Directive)('@privilege(category: "figure", privilege: "query", domainOwnerGranted: true)'),
301
343
  (0, type_graphql_1.Query)(returns => [figure_history_js_1.FigureHistory], { description: 'Released versions of a figure, newest first.' }),
@@ -362,6 +404,13 @@ tslib_1.__decorate([
362
404
  tslib_1.__metadata("design:paramtypes", [String, Object, String]),
363
405
  tslib_1.__metadata("design:returntype", Promise)
364
406
  ], FigureQuery.prototype, "inspectFigureDraft", null);
407
+ tslib_1.__decorate([
408
+ (0, type_graphql_1.Directive)('@privilege(category: "figure", privilege: "query", domainOwnerGranted: true)'),
409
+ (0, type_graphql_1.Query)(returns => [String], { nullable: true, description: 'The categories this server allows, or null when a category is free text.' }),
410
+ tslib_1.__metadata("design:type", Function),
411
+ tslib_1.__metadata("design:paramtypes", []),
412
+ tslib_1.__metadata("design:returntype", Promise)
413
+ ], FigureQuery.prototype, "figureCategories", null);
365
414
  tslib_1.__decorate([
366
415
  (0, type_graphql_1.Directive)('@privilege(category: "figure", privilege: "query", domainOwnerGranted: true)'),
367
416
  (0, type_graphql_1.Query)(returns => [String], { description: 'All figure type names in scope — used to check name collisions before create.' }),
@@ -404,6 +453,11 @@ async function releasedSourceOfName(domainId, name) {
404
453
  const found = await releasedSourceOf(domainId, name.type);
405
454
  return found && found.figure.namespace === name.namespace ? found : null;
406
455
  }
456
+ /** The released source of another domain's public figure by full name (G2): looked at after the reader's own. */
457
+ async function publicReleasedSourceOf(name) {
458
+ const figure = await (0, figure_public_js_1.publicFigureOfName)(name.namespace, name.type);
459
+ return figure?.domain ? releasedSourceOfName(figure.domain.id, name) : null;
460
+ }
407
461
  /** One numbered release of a figure, or null when it has none by that number. */
408
462
  async function releaseNumbered(figure, version) {
409
463
  const row = await (0, shell_1.getRepository)(figure_history_js_1.FigureHistory).findOne({
@@ -1 +1 @@
1
- {"version":3,"file":"figure-query.js","sourceRoot":"","sources":["../../../server/service/figure/figure-query.ts"],"names":[],"mappings":"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","sourcesContent":["import { In } from 'typeorm'\nimport { Args, Arg, Ctx, Directive, Int, Query, Resolver, UseMiddleware } from 'type-graphql'\nimport { GraphQLJSON } from 'graphql-scalars'\n\nimport {\n Domain,\n getQueryBuilderFromListParams,\n getRepository,\n ListParam,\n Refusal,\n SpeakRefusals,\n refusalKey\n} from '@things-factory/shell'\nimport { formatFigureRef, parseFigureName, type FigureName } from '@hatiolab/figure-model'\n\nimport { Figure } from './figure.js'\nimport { FigureHistory } from './figure-history.js'\nimport { consumablePayloadOf, inspectSource } from './figure-format.js'\nimport { FigureInspection, FigureList, FigureProposalOutcome } from './figure-type.js'\nimport { FigureReplacedDraft } from './figure-replaced-draft.js'\nimport { replacedDraftsOf } from './figure-revert.js'\nimport { proposalOutcomeOf } from './figure-proposal.js'\nimport { meshSummaryOf } from './figure-mesh-store.js'\n\n@Resolver(Figure)\n@UseMiddleware(SpeakRefusals)\nexport class FigureQuery {\n @Directive('@privilege(category: \"figure\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(returns => Figure, { nullable: true, description: 'Finds a single figure by its ID.' })\n async figure(@Arg('id') id: string, @Ctx() context: ResolverContext): Promise<Figure> {\n const { domain } = context.state\n\n // 부모 도메인의 Figure 도 보인다 — Board 와 같은 범위 규칙이다.\n return await getRepository(Figure).findOne({\n where: { domain: { id: In([domain.id, domain.parentId].filter(Boolean)) }, id }\n })\n }\n\n @Directive('@privilege(category: \"figure\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(returns => FigureList, { description: 'Lists figures. Sortable by score, triangles, name, updatedAt.' })\n async figures(@Args() params: ListParam, @Ctx() context: ResolverContext): Promise<FigureList> {\n const { domain } = context.state\n\n const queryBuilder = getQueryBuilderFromListParams({\n repository: getRepository(Figure),\n params,\n domain,\n alias: 'figure',\n /*\n `tags` 도 찾을 수 있어야 한다 — 태그의 값은 붙이는 데 있지 않고 **찾는 데** 있다.\n\n `simple-json` 이라 칸에는 `[\"반출\",\"자동\"]` 이 통째로 들어 있고, LIKE 는 그 글자를\n 본다. 「반출」로 찾으면 걸린다. 정확히 그 태그만 걸리는 것은 아니지만(이름에 「반출」이\n 든 도형도 걸린다) 찾기로는 그것이 오히려 낫다.\n */\n searchables: ['type', 'name', 'description', 'category', 'tags']\n })\n\n const [items, total] = await queryBuilder.getManyAndCount()\n\n return { items, total }\n }\n\n /**\n * 등록된 타입 이름 목록.\n *\n * 저작 화면이 **새 타입 이름이 이미 쓰이는지** 물어보는 데 쓴다. `type` 은 저장되는\n * 식별자라 만든 뒤에 고칠 수 없으므로, 만들기 전에 알려 줘야 한다.\n *\n * `state` 로 걸러지지 않는다 — `draft` 인 Figure 의 이름도 이미 점유된 것이다.\n */\n /**\n * 발행된 판들 — 최근 것부터.\n *\n * 저작 중 저장은 여기 없다. 판본은 발행에서만 생기므로(`releaseFigure`), 이 목록이 곧\n * 「이 도형이 몇 번 약속되었나」다.\n */\n @Directive('@privilege(category: \"figure\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(returns => [FigureHistory], { description: 'Released versions of a figure, newest first.' })\n async figureVersions(@Arg('id') id: string, @Ctx() context: ResolverContext): Promise<FigureHistory[]> {\n const { domain } = context.state\n\n return await getRepository(FigureHistory).find({\n where: { domain: { id: In([domain.id, domain.parentId].filter(Boolean)) }, originalId: id },\n relations: ['updater'],\n order: { version: 'DESC' },\n take: 10\n })\n }\n\n /**\n * 지금 소비처가 쓰는 판.\n *\n * 도형의 현재 정본은 저작 중일 수 있다(초안). 배치된 것이 보는 것은 **마지막으로 발행된 판**이고,\n * 그것을 이 자리가 답한다.\n */\n /** What a kept GLB holds, read again from its bytes (ADR-0129): the modeller asks when it reopens a figure. */\n @Directive('@privilege(category: \"figure\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(returns => GraphQLJSON, { nullable: true, description: 'What a kept GLB holds, by its hash: bounds in mm, triangles, primitives and nodes. None when this domain does not hold it.' })\n async figureMeshSummary(@Arg('hash') hash: string, @Ctx() context: ResolverContext): Promise<unknown> {\n const { domain, tx } = context.state\n return (await meshSummaryOf(getRepository(Figure, tx).manager, domain, hash)) ?? null\n }\n\n /** What became of an AI proposal: the figures a save put it into (ADR-0097 §5.6 item 5). */\n @Directive('@privilege(category: \"figure\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(returns => [FigureProposalOutcome], {\n description: 'The figures an AI proposal was saved into, oldest first. None: it was not saved, or not in this domain.'\n })\n async figureProposalOutcome(@Arg('proposalKey') proposalKey: string, @Ctx() context: ResolverContext): Promise<FigureProposalOutcome[]> {\n const { domain, tx } = context.state\n return await proposalOutcomeOf(getRepository(Figure, tx).manager, domain, proposalKey)\n }\n\n /** The drafts reverts kept for a figure, newest first -- apart from its released versions (ADR-0097 §5.6). */\n @Directive('@privilege(category: \"figure\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(returns => [FigureReplacedDraft], { description: 'Drafts kept when a revert wrote over them, newest first. Not released versions.' })\n async figureReplacedDrafts(@Arg('id') id: string, @Ctx() context: ResolverContext): Promise<FigureReplacedDraft[]> {\n const { domain, tx } = context.state\n return await replacedDraftsOf(getRepository(FigureReplacedDraft, tx).manager, domain, id)\n }\n\n @Directive('@privilege(category: \"figure\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(returns => FigureHistory, { nullable: true, description: 'The most recently released version of a figure.' })\n async figureReleased(@Arg('id') id: string, @Ctx() context: ResolverContext): Promise<FigureHistory> {\n const { domain } = context.state\n\n return await getRepository(FigureHistory).findOne({\n where: { domain: { id: In([domain.id, domain.parentId].filter(Boolean)) }, originalId: id },\n order: { version: 'DESC' }\n })\n }\n\n /**\n * 발행해도 되나 — **누르기 전에** 묻는 자리.\n *\n * 판정은 `figure-gate.ts` 가 하고 이 자리는 정본을 꺼내 넘긴다. 같은 판정을 `releaseFigure` 도\n * 부른다 — 화면이 물어 보고 통과했더라도 그 사이에 정본이 바뀌었을 수 있으므로, 막는 것은 언제나\n * 뮤테이션이다. 이 질의는 **이유를 미리 보여 주기 위한 것**이고 허가증이 아니다.\n */\n @Directive('@privilege(category: \"figure\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(returns => FigureInspection, { description: 'Whether a figure may be released, with the reasons.' })\n async inspectFigure(@Arg('id') id: string, @Ctx() context: ResolverContext): Promise<FigureInspection> {\n const { domain } = context.state\n\n const figure = await getRepository(Figure).findOne({\n where: { domain: { id: In([domain.id, domain.parentId].filter(Boolean)) }, id },\n /*\n `type` is read too. A asset carries no type, so the temporary-type refusal reads the row's; with only\n id and source selected it saw `undefined`, the panel enabled 「발행하기」, and the release mutation — which\n loads the whole row — refused on the press (2026-09-24).\n */\n select: { id: true, source: true, type: true }\n })\n\n if (!figure) {\n throw new Error(`Figure ${id} 를 찾을 수 없다`)\n }\n\n /*\n **화면이 발행 문과 같은 것을 본다.** 직전 발행판을 여기서도 함께 넘기지 않으면, 저작 화면은\n 조용한데 발행을 누른 순간 계약 위반으로 막힌다 — 그때는 이미 열 군데를 고친 뒤다.\n */\n const released = await getRepository(FigureHistory)\n .createQueryBuilder('history')\n .where('history.originalId = :id', { id })\n .orderBy('history.version', 'DESC')\n .limit(1)\n .getOne()\n\n return inspectSource(figure.source, released?.source, context.t, figure.type)\n }\n\n /**\n * The same judgement for a source that has not been saved — what the modeller shows **while** the author edits.\n *\n * Without it a author saw nothing until they saved and opened the release panel. The judgement runs here, not\n * in the browser, because the sentences are made from the request's language (`inspectAnySource` with `context.t`)\n * and a second copy on the screen would drift from the one the release refuses with. When `id` names a saved\n * figure, its row type and last release are read as `inspectFigure` does; a figure never saved has neither.\n */\n @Directive('@privilege(category: \"figure\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(returns => FigureInspection, { description: 'Whether an unsaved figure source would be released, with the reasons.' })\n async inspectFigureDraft(\n @Arg('source') source: string,\n @Ctx() context: ResolverContext,\n @Arg('id', { nullable: true }) id?: string\n ): Promise<FigureInspection> {\n const { domain } = context.state\n if (!id) return inspectSource(source, null, context.t)\n\n const figure = await getRepository(Figure).findOne({\n where: { domain: { id: In([domain.id, domain.parentId].filter(Boolean)) }, id },\n select: { id: true, type: true }\n })\n if (!figure) throw new Error(`Figure ${id} 를 찾을 수 없다`)\n\n const released = await getRepository(FigureHistory)\n .createQueryBuilder('history')\n .where('history.originalId = :id', { id })\n .orderBy('history.version', 'DESC')\n .limit(1)\n .getOne()\n\n return inspectSource(source, released?.source, context.t, figure.type)\n }\n\n @Directive('@privilege(category: \"figure\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(returns => [String], { description: 'All figure type names in scope — used to check name collisions before create.' })\n async figureTypeNames(@Ctx() context: ResolverContext): Promise<string[]> {\n const { domain } = context.state\n\n const rows = await getRepository(Figure).find({\n where: { domain: { id: In([domain.id, domain.parentId].filter(Boolean)) } },\n select: { type: true }\n })\n\n return rows.map(r => r.type).filter(Boolean)\n }\n\n /**\n * 소비처(operato-board, operato-twin, things-scene)가 발행된 도형을 받아 가는 문.\n *\n * 이름은 보드와의 계약이라 그대로 둔다(바꾸는 일은 따로 한다). 돌려주는 것은 자산이다 —\n * `{ type, asset }`. 그리는 쪽(`registerFigure`)이 커널로 컴파일한다.\n *\n * ## 규칙\n * 1. 소비처는 초안(draft)을 볼 수 없다 — **반드시 발행된(released) 판만 전달**한다.\n * 2. 현재 Figure가 released 상태이면 현재 source를 넘긴다.\n * 3. 현재 Figure가 저작 중(draft)이더라도 이전에 발행된 이력(FigureHistory)이 있으면\n * 가장 최근의 released 판본을 넘긴다.\n * 4. 한 번도 발행된 적 없는 초안 자산이거나 존재하지 않는 타입인 경우 null을 반환하여\n * 미완성 자산이 씬 화면에 유출되는 것을 엄격히 차단한다.\n * 5. 도메인 상속 시 자식 도메인의 타입이 부모 도메인의 동일 타입을 항상 오버라이드한다.\n * 6. 권한은 저작(`figure`)과 **다른 category** 인 `figure-published` 다. 소비처 사용자에게\n * 저작 권한을 요구하면 board·twin 의 팔레트가 안 뜨고, 그렇다고 선언을 비우면 이 집에서는\n * 로그인조차 안 한 사람에게 열린다(`auth-rebuild.md` §1). `<module>-published` 는\n * 「그 모듈이 발행한 것을 남이 읽는 문」이라는 규약이다 — 아키텍트 판정(2026-09-15).\n *\n * ## 열거는 막혀 있다 — 지금은 우연이다\n *\n * 이 문의 열쇠는 `type` 하나뿐이라 이름을 모르면 못 꺼낸다. 그런데 그것이 **설계가 아니다** —\n * 목록을 내는 `figures`·`figureTypeNames` 가 `figure` category 로 잠겨 있어서 결과적으로\n * 그런 것뿐이다. 나중에 누가 소비처용 목록 문을 하나 더 열고 `figure-published` 를 붙이면\n * 열거가 함께 열리고, 「이름을 알아야 한다」에 기대고 있던 가정이 조용히 사라진다.\n * 그 문을 낼 사람이 이 단락을 읽고 그때 정하면 된다.\n */\n /*\n This directive is attached by schema assembly, so a test that calls the resolver method\n directly never exercises it. `figure-blueprint-query.test.ts` reads this source for the\n declaration instead — see the test named for it there.\n */\n @Directive('@privilege(category: \"figure-published\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(returns => GraphQLJSON, {\n nullable: true,\n description:\n 'A released figure for its consumers (board, twin, things-scene): { type, version, asset }. The latest release, or the one numbered `version` for a consumer that pins releases (ADR-0104). Only returns released figures.'\n })\n async figureBlueprint(\n @Arg('type') type: string,\n @Ctx() context: ResolverContext,\n @Arg('version', type => Int, { nullable: true, description: 'A release number. Absent: the latest release.' }) pinned?: number\n ): Promise<any> {\n const { domain } = context.state\n\n /*\n A child domain shadows the same type in its parent, which is how a tenant replaces the standard\n CONVEYOR with its own. Only a released version shadows. When the child has just a draft, the\n parent's release is used, so starting a draft never makes placed figures disappear (chief\n architect ruling, 2026-09-17). This used to skip the fallback as soon as a child row existed and\n return null.\n */\n const latest =\n (await releasedSourceOf(domain.id, type)) ?? (domain.parentId ? await releasedSourceOf(domain.parentId, type) : null)\n\n if (!latest) {\n return null\n }\n\n /*\n A pinned release is read from the same figure the latest comes from -- the shadowing rule decides whose\n releases these are, then the number picks one. Releases are never deleted, so a number once handed out is\n always there; a number that never was is refused by name rather than answered with another release.\n */\n const found = pinned === undefined || pinned === null || pinned === latest.version ? latest : await releaseNumbered(latest.figure, pinned)\n if (!found) {\n throw new Refusal(\n 'figure-release-not-found',\n { type, version: pinned, latest: latest.version },\n '{type} has no release {version}. its latest release is {latest}.'\n )\n }\n\n const { figure, source: sourceToCompile, version } = found\n\n try {\n const text = typeof sourceToCompile === 'string' ? sourceToCompile : JSON.stringify(sourceToCompile)\n return { type, version, asset: consumablePayloadOf(text).asset }\n } catch (err) {\n console.error(`[figureBlueprint] 타입 '${type}' (figure id: ${figure.id}) 자산 컴파일 실패:`, err)\n\n /*\n Null says one thing here: nobody published this type (ADR-0063 결정 2 보탬). A released figure\n whose stored source no longer compiles is a different fact, and answering null for it makes the\n board draw a stand-in with the reason nowhere on screen — the author published, the catalogue\n says released, and the only trace is the line above. That is the silence ADR-0053 refuses.\n\n The board asks per type inside a Promise.all and collects a rejection into `failed`, so this\n refusal costs that one figure its drawing and the scene still opens.\n */\n throw new Refusal(\n 'figure-release-does-not-compile',\n { type, figureId: figure.id, version },\n 'the released source of {type} does not compile. open it in the modeller and release it again.'\n )\n }\n }\n\n /**\n * Released figures a board asks for together, by full name `{namespace}/{type}` (ADR-0114 결정 14).\n *\n * One answer per name: an item, or a refusal that names why. A refusal never takes another item away -- the board\n * draws what it got and a stand-in with the reason for the rest. This server keeps its policy: the latest release,\n * shadowed by the child domain as `figureBlueprint` does. A type map is the board server's.\n */\n @Directive('@privilege(category: \"figure-published\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(returns => GraphQLJSON, {\n description:\n 'Released figures asked together by full name {namespace}/{type}: { items: [{ type, ref, asset }], refused: [{ type, code, message }] }. The latest release of each; one refusal never removes another item.'\n })\n async figureBlueprints(\n @Arg('types', type => [String], { description: 'Full figure names {namespace}/{type}. At most 500.' }) types: string[],\n @Ctx() context: ResolverContext\n ): Promise<any> {\n const { domain } = context.state\n const names = [...new Set(types)]\n if (names.length > FIGURE_BLUEPRINTS_MAX) {\n throw new Refusal('figure-names-too-many', { count: names.length, max: FIGURE_BLUEPRINTS_MAX }, 'at most {max} figure names can be asked at once, not {count}.')\n }\n\n const items: { type: string; ref: string; asset: unknown }[] = []\n const refused: { type: string; code: string; message: string }[] = []\n /* Plain text: a board draws the reason on a canvas, so a name with `/` is not escaped. */\n const refuse = (type: string, refusal: Refusal) =>\n refused.push({\n type,\n code: refusal.code,\n message: context.t\n ? context.t(refusalKey(refusal.code), { ...refusal.params, defaultValue: refusal.message, interpolation: { escapeValue: false } })\n : refusal.message\n })\n\n for (const type of names) {\n const name = parseFigureName(type)\n if (!name) {\n refuse(type, new Refusal('figure-name-malformed', { type }, '{type} is not a full figure name of the form namespace/type.'))\n continue\n }\n const found =\n (await releasedSourceOfName(domain.id, name)) ?? (domain.parentId ? await releasedSourceOfName(domain.parentId, name) : null)\n if (!found) {\n refuse(type, new Refusal('figure-not-released', { type }, 'no release is published here.'))\n continue\n }\n try {\n items.push({ type, ref: formatFigureRef({ ...name, version: found.version }), asset: consumablePayloadOf(found.source).asset })\n } catch {\n refuse(\n type,\n new Refusal(\n 'figure-release-does-not-compile',\n { type, figureId: found.figure.id, version: found.version },\n 'the released source of {type} does not compile. open it in the modeller and release it again.'\n )\n )\n }\n }\n\n return { items, refused }\n }\n}\n\nconst FIGURE_BLUEPRINTS_MAX = 500\n\n/** The released source of a full name in one domain: the type there, published under that namespace. */\nasync function releasedSourceOfName(domainId: string, name: FigureName) {\n const found = await releasedSourceOf(domainId, name.type)\n return found && found.figure.namespace === name.namespace ? found : null\n}\n\n/** One numbered release of a figure, or null when it has none by that number. */\nasync function releaseNumbered(figure: Figure, version: number): Promise<{ figure: Figure; source: string; version: number } | null> {\n const row = await getRepository(FigureHistory).findOne({\n where: { originalId: figure.id, state: 'released', version }\n })\n return row?.source ? { figure, source: row.source, version: row.version } : null\n}\n\n/**\n * Finds the released source of a type in one domain, or null.\n *\n * A released row gives its own source; a draft row gives the source of its latest released history.\n * A figure that was never released gives null, because drafts never reach consumers.\n */\nasync function releasedSourceOf(\n domainId: string,\n type: string\n): Promise<{ figure: Figure; source: string; version: number } | null> {\n const figure = await getRepository(Figure).findOne({ where: { domain: { id: domainId }, type } })\n if (!figure) return null\n\n if (figure.state === 'released' && figure.source) {\n return { figure, source: figure.source, version: figure.version }\n }\n\n const latestReleased = await getRepository(FigureHistory).findOne({\n where: { domain: { id: domainId }, originalId: figure.id, state: 'released' },\n order: { version: 'DESC' }\n })\n\n /* The version travels with the source: a refusal names the edition that does not compile, and the\n row's own version is the draft being edited, not the one the board was handed. */\n return latestReleased?.source\n ? { figure, source: latestReleased.source, version: latestReleased.version }\n : null\n}\n"]}
1
+ {"version":3,"file":"figure-query.js","sourceRoot":"","sources":["../../../server/service/figure/figure-query.ts"],"names":[],"mappings":"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","sourcesContent":["import { In } from 'typeorm'\nimport { Args, Arg, Ctx, Directive, Int, Query, Resolver, UseMiddleware } from 'type-graphql'\nimport { GraphQLJSON } from 'graphql-scalars'\n\nimport {\n Domain,\n getQueryBuilderFromListParams,\n getRepository,\n ListParam,\n Refusal,\n SpeakRefusals,\n refusalKey\n} from '@things-factory/shell'\nimport { formatFigureRef, parseFigureName, type FigureName } from '@hatiolab/figure-model'\n\nimport { Figure } from './figure.js'\nimport { FigureHistory } from './figure-history.js'\nimport { consumablePayloadOf, inspectSource } from './figure-format.js'\nimport { FigureInspection, FigureList, FigureProposalOutcome } from './figure-type.js'\nimport { FigureReplacedDraft } from './figure-replaced-draft.js'\nimport { replacedDraftsOf } from './figure-revert.js'\nimport { proposalOutcomeOf } from './figure-proposal.js'\nimport { meshSummaryOf } from './figure-mesh-store.js'\nimport { readableFigure, publicFigureOfName } from './figure-public.js'\nimport { figureCategories } from './figure-categories.js'\n\n@Resolver(Figure)\n@UseMiddleware(SpeakRefusals)\nexport class FigureQuery {\n @Directive('@privilege(category: \"figure\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(returns => Figure, { nullable: true, description: 'Finds a single figure by its ID.' })\n async figure(@Arg('id') id: string, @Ctx() context: ResolverContext): Promise<Figure> {\n const { domain } = context.state\n\n // 부모 도메인의 Figure 도 보인다 — Board 와 같은 범위 규칙이다.\n return await getRepository(Figure).findOne({\n where: { domain: { id: In([domain.id, domain.parentId].filter(Boolean)) }, id }\n })\n }\n\n @Directive('@privilege(category: \"figure\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(returns => FigureList, { description: 'Lists figures. Sortable by score, triangles, name, updatedAt.' })\n async figures(@Args() params: ListParam, @Ctx() context: ResolverContext): Promise<FigureList> {\n const { domain } = context.state\n\n const queryBuilder = getQueryBuilderFromListParams({\n repository: getRepository(Figure),\n params,\n domain,\n alias: 'figure',\n /*\n `tags` 도 찾을 수 있어야 한다 — 태그의 값은 붙이는 데 있지 않고 **찾는 데** 있다.\n\n `simple-json` 이라 칸에는 `[\"반출\",\"자동\"]` 이 통째로 들어 있고, LIKE 는 그 글자를\n 본다. 「반출」로 찾으면 걸린다. 정확히 그 태그만 걸리는 것은 아니지만(이름에 「반출」이\n 든 도형도 걸린다) 찾기로는 그것이 오히려 낫다.\n */\n searchables: ['type', 'name', 'description', 'category', 'tags']\n })\n\n const [items, total] = await queryBuilder.getManyAndCount()\n\n return { items, total }\n }\n\n /**\n * Other domains' public figures (LV figure-server design G2): what this domain may read, package and draw besides its\n * own and its parent's. The rows carry their domain, so a screen says whose each is. Their drafts are not opened.\n */\n @Directive('@privilege(category: \"figure\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(returns => FigureList, { description: \"Other domains' public figures. Read only: their releases, never their drafts.\" })\n async publicFigures(@Args() params: ListParam, @Ctx() context: ResolverContext): Promise<FigureList> {\n const { domain } = context.state\n const mine = [domain.id, domain.parentId].filter(Boolean)\n const queryBuilder = getQueryBuilderFromListParams({\n repository: getRepository(Figure),\n params,\n alias: 'figure',\n searchables: ['type', 'name', 'description', 'category', 'tags']\n })\n .leftJoinAndSelect('figure.domain', 'owner')\n .andWhere('figure.public = :public', { public: true })\n .andWhere('owner.id NOT IN (:...mine)', { mine })\n const [items, total] = await queryBuilder.getManyAndCount()\n return { items, total }\n }\n\n /**\n * 등록된 타입 이름 목록.\n *\n * 저작 화면이 **새 타입 이름이 이미 쓰이는지** 물어보는 데 쓴다. `type` 은 저장되는\n * 식별자라 만든 뒤에 고칠 수 없으므로, 만들기 전에 알려 줘야 한다.\n *\n * `state` 로 걸러지지 않는다 — `draft` 인 Figure 의 이름도 이미 점유된 것이다.\n */\n /**\n * 발행된 판들 — 최근 것부터.\n *\n * 저작 중 저장은 여기 없다. 판본은 발행에서만 생기므로(`releaseFigure`), 이 목록이 곧\n * 「이 도형이 몇 번 약속되었나」다.\n */\n @Directive('@privilege(category: \"figure\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(returns => [FigureHistory], { description: 'Released versions of a figure, newest first.' })\n async figureVersions(@Arg('id') id: string, @Ctx() context: ResolverContext): Promise<FigureHistory[]> {\n const { domain } = context.state\n\n /* Its own, its parent's, or another domain's public figure (G2): releases are what a public figure shows. */\n if (!(await readableFigure(domain, id, { id: true, public: true, domain: { id: true } }))) return []\n return await getRepository(FigureHistory).find({\n where: { originalId: id },\n relations: ['updater'],\n order: { version: 'DESC' },\n take: 10\n })\n }\n\n /**\n * 지금 소비처가 쓰는 판.\n *\n * 도형의 현재 정본은 저작 중일 수 있다(초안). 배치된 것이 보는 것은 **마지막으로 발행된 판**이고,\n * 그것을 이 자리가 답한다.\n */\n /** What a kept GLB holds, read again from its bytes (ADR-0129): the modeller asks when it reopens a figure. */\n @Directive('@privilege(category: \"figure\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(returns => GraphQLJSON, { nullable: true, description: 'What a kept GLB holds, by its hash: bounds in mm, triangles, primitives and nodes. None when this domain does not hold it.' })\n async figureMeshSummary(@Arg('hash') hash: string, @Ctx() context: ResolverContext): Promise<unknown> {\n const { domain, tx } = context.state\n return (await meshSummaryOf(getRepository(Figure, tx).manager, domain, hash)) ?? null\n }\n\n /** What became of an AI proposal: the figures a save put it into (ADR-0097 §5.6 item 5). */\n @Directive('@privilege(category: \"figure\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(returns => [FigureProposalOutcome], {\n description: 'The figures an AI proposal was saved into, oldest first. None: it was not saved, or not in this domain.'\n })\n async figureProposalOutcome(@Arg('proposalKey') proposalKey: string, @Ctx() context: ResolverContext): Promise<FigureProposalOutcome[]> {\n const { domain, tx } = context.state\n return await proposalOutcomeOf(getRepository(Figure, tx).manager, domain, proposalKey)\n }\n\n /** The drafts reverts kept for a figure, newest first -- apart from its released versions (ADR-0097 §5.6). */\n @Directive('@privilege(category: \"figure\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(returns => [FigureReplacedDraft], { description: 'Drafts kept when a revert wrote over them, newest first. Not released versions.' })\n async figureReplacedDrafts(@Arg('id') id: string, @Ctx() context: ResolverContext): Promise<FigureReplacedDraft[]> {\n const { domain, tx } = context.state\n return await replacedDraftsOf(getRepository(FigureReplacedDraft, tx).manager, domain, id)\n }\n\n @Directive('@privilege(category: \"figure\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(returns => FigureHistory, { nullable: true, description: 'The most recently released version of a figure.' })\n async figureReleased(@Arg('id') id: string, @Ctx() context: ResolverContext): Promise<FigureHistory> {\n const { domain } = context.state\n\n if (!(await readableFigure(domain, id, { id: true, public: true, domain: { id: true } }))) return null\n return await getRepository(FigureHistory).findOne({\n where: { originalId: id },\n order: { version: 'DESC' }\n })\n }\n\n /**\n * 발행해도 되나 — **누르기 전에** 묻는 자리.\n *\n * 판정은 `figure-gate.ts` 가 하고 이 자리는 정본을 꺼내 넘긴다. 같은 판정을 `releaseFigure` 도\n * 부른다 — 화면이 물어 보고 통과했더라도 그 사이에 정본이 바뀌었을 수 있으므로, 막는 것은 언제나\n * 뮤테이션이다. 이 질의는 **이유를 미리 보여 주기 위한 것**이고 허가증이 아니다.\n */\n @Directive('@privilege(category: \"figure\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(returns => FigureInspection, { description: 'Whether a figure may be released, with the reasons.' })\n async inspectFigure(@Arg('id') id: string, @Ctx() context: ResolverContext): Promise<FigureInspection> {\n const { domain } = context.state\n\n const figure = await getRepository(Figure).findOne({\n where: { domain: { id: In([domain.id, domain.parentId].filter(Boolean)) }, id },\n /*\n `type` is read too. A asset carries no type, so the temporary-type refusal reads the row's; with only\n id and source selected it saw `undefined`, the panel enabled 「발행하기」, and the release mutation — which\n loads the whole row — refused on the press (2026-09-24).\n */\n select: { id: true, source: true, type: true }\n })\n\n if (!figure) {\n throw new Error(`Figure ${id} 를 찾을 수 없다`)\n }\n\n /*\n **화면이 발행 문과 같은 것을 본다.** 직전 발행판을 여기서도 함께 넘기지 않으면, 저작 화면은\n 조용한데 발행을 누른 순간 계약 위반으로 막힌다 — 그때는 이미 열 군데를 고친 뒤다.\n */\n const released = await getRepository(FigureHistory)\n .createQueryBuilder('history')\n .where('history.originalId = :id', { id })\n .orderBy('history.version', 'DESC')\n .limit(1)\n .getOne()\n\n return inspectSource(figure.source, released?.source, context.t, figure.type, figure.category)\n }\n\n /**\n * The same judgement for a source that has not been saved — what the modeller shows **while** the author edits.\n *\n * Without it a author saw nothing until they saved and opened the release panel. The judgement runs here, not\n * in the browser, because the sentences are made from the request's language (`inspectAnySource` with `context.t`)\n * and a second copy on the screen would drift from the one the release refuses with. When `id` names a saved\n * figure, its row type and last release are read as `inspectFigure` does; a figure never saved has neither.\n */\n @Directive('@privilege(category: \"figure\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(returns => FigureInspection, { description: 'Whether an unsaved figure source would be released, with the reasons.' })\n async inspectFigureDraft(\n @Arg('source') source: string,\n @Ctx() context: ResolverContext,\n @Arg('id', { nullable: true }) id?: string\n ): Promise<FigureInspection> {\n const { domain } = context.state\n if (!id) return inspectSource(source, null, context.t)\n\n const figure = await getRepository(Figure).findOne({\n where: { domain: { id: In([domain.id, domain.parentId].filter(Boolean)) }, id },\n select: { id: true, type: true }\n })\n if (!figure) throw new Error(`Figure ${id} 를 찾을 수 없다`)\n\n const released = await getRepository(FigureHistory)\n .createQueryBuilder('history')\n .where('history.originalId = :id', { id })\n .orderBy('history.version', 'DESC')\n .limit(1)\n .getOne()\n\n return inspectSource(source, released?.source, context.t, figure.type, figure.category)\n }\n\n /** The categories this server allows (G5), or null when a category is free text: the modeller offers them to choose from. */\n @Directive('@privilege(category: \"figure\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(returns => [String], { nullable: true, description: 'The categories this server allows, or null when a category is free text.' })\n async figureCategories(): Promise<string[] | null> {\n const codes = figureCategories()\n return codes ? [...codes] : null\n }\n\n @Directive('@privilege(category: \"figure\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(returns => [String], { description: 'All figure type names in scope — used to check name collisions before create.' })\n async figureTypeNames(@Ctx() context: ResolverContext): Promise<string[]> {\n const { domain } = context.state\n\n const rows = await getRepository(Figure).find({\n where: { domain: { id: In([domain.id, domain.parentId].filter(Boolean)) } },\n select: { type: true }\n })\n\n return rows.map(r => r.type).filter(Boolean)\n }\n\n /**\n * 소비처(operato-board, operato-twin, things-scene)가 발행된 도형을 받아 가는 문.\n *\n * 이름은 보드와의 계약이라 그대로 둔다(바꾸는 일은 따로 한다). 돌려주는 것은 자산이다 —\n * `{ type, asset }`. 그리는 쪽(`registerFigure`)이 커널로 컴파일한다.\n *\n * ## 규칙\n * 1. 소비처는 초안(draft)을 볼 수 없다 — **반드시 발행된(released) 판만 전달**한다.\n * 2. 현재 Figure가 released 상태이면 현재 source를 넘긴다.\n * 3. 현재 Figure가 저작 중(draft)이더라도 이전에 발행된 이력(FigureHistory)이 있으면\n * 가장 최근의 released 판본을 넘긴다.\n * 4. 한 번도 발행된 적 없는 초안 자산이거나 존재하지 않는 타입인 경우 null을 반환하여\n * 미완성 자산이 씬 화면에 유출되는 것을 엄격히 차단한다.\n * 5. 도메인 상속 시 자식 도메인의 타입이 부모 도메인의 동일 타입을 항상 오버라이드한다.\n * 6. 권한은 저작(`figure`)과 **다른 category** 인 `figure-published` 다. 소비처 사용자에게\n * 저작 권한을 요구하면 board·twin 의 팔레트가 안 뜨고, 그렇다고 선언을 비우면 이 집에서는\n * 로그인조차 안 한 사람에게 열린다(`auth-rebuild.md` §1). `<module>-published` 는\n * 「그 모듈이 발행한 것을 남이 읽는 문」이라는 규약이다 — 아키텍트 판정(2026-09-15).\n *\n * ## 열거는 막혀 있다 — 지금은 우연이다\n *\n * 이 문의 열쇠는 `type` 하나뿐이라 이름을 모르면 못 꺼낸다. 그런데 그것이 **설계가 아니다** —\n * 목록을 내는 `figures`·`figureTypeNames` 가 `figure` category 로 잠겨 있어서 결과적으로\n * 그런 것뿐이다. 나중에 누가 소비처용 목록 문을 하나 더 열고 `figure-published` 를 붙이면\n * 열거가 함께 열리고, 「이름을 알아야 한다」에 기대고 있던 가정이 조용히 사라진다.\n * 그 문을 낼 사람이 이 단락을 읽고 그때 정하면 된다.\n */\n /*\n This directive is attached by schema assembly, so a test that calls the resolver method\n directly never exercises it. `figure-blueprint-query.test.ts` reads this source for the\n declaration instead — see the test named for it there.\n */\n @Directive('@privilege(category: \"figure-published\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(returns => GraphQLJSON, {\n nullable: true,\n description:\n 'A released figure for its consumers (board, twin, things-scene): { type, version, asset }. The latest release, or the one numbered `version` for a consumer that pins releases (ADR-0104). Only returns released figures.'\n })\n async figureBlueprint(\n @Arg('type') type: string,\n @Ctx() context: ResolverContext,\n @Arg('version', type => Int, { nullable: true, description: 'A release number. Absent: the latest release.' }) pinned?: number\n ): Promise<any> {\n const { domain } = context.state\n\n /*\n A child domain shadows the same type in its parent, which is how a tenant replaces the standard\n CONVEYOR with its own. Only a released version shadows. When the child has just a draft, the\n parent's release is used, so starting a draft never makes placed figures disappear (chief\n architect ruling, 2026-09-17). This used to skip the fallback as soon as a child row existed and\n return null.\n */\n const latest =\n (await releasedSourceOf(domain.id, type)) ?? (domain.parentId ? await releasedSourceOf(domain.parentId, type) : null)\n\n if (!latest) {\n return null\n }\n\n /*\n A pinned release is read from the same figure the latest comes from -- the shadowing rule decides whose\n releases these are, then the number picks one. Releases are never deleted, so a number once handed out is\n always there; a number that never was is refused by name rather than answered with another release.\n */\n const found = pinned === undefined || pinned === null || pinned === latest.version ? latest : await releaseNumbered(latest.figure, pinned)\n if (!found) {\n throw new Refusal(\n 'figure-release-not-found',\n { type, version: pinned, latest: latest.version },\n '{type} has no release {version}. its latest release is {latest}.'\n )\n }\n\n const { figure, source: sourceToCompile, version } = found\n\n try {\n const text = typeof sourceToCompile === 'string' ? sourceToCompile : JSON.stringify(sourceToCompile)\n return { type, version, asset: consumablePayloadOf(text).asset }\n } catch (err) {\n console.error(`[figureBlueprint] 타입 '${type}' (figure id: ${figure.id}) 자산 컴파일 실패:`, err)\n\n /*\n Null says one thing here: nobody published this type (ADR-0063 결정 2 보탬). A released figure\n whose stored source no longer compiles is a different fact, and answering null for it makes the\n board draw a stand-in with the reason nowhere on screen — the author published, the catalogue\n says released, and the only trace is the line above. That is the silence ADR-0053 refuses.\n\n The board asks per type inside a Promise.all and collects a rejection into `failed`, so this\n refusal costs that one figure its drawing and the scene still opens.\n */\n throw new Refusal(\n 'figure-release-does-not-compile',\n { type, figureId: figure.id, version },\n 'the released source of {type} does not compile. open it in the modeller and release it again.'\n )\n }\n }\n\n /**\n * Released figures a board asks for together, by full name `{namespace}/{type}` (ADR-0114 결정 14).\n *\n * One answer per name: an item, or a refusal that names why. A refusal never takes another item away -- the board\n * draws what it got and a stand-in with the reason for the rest. This server keeps its policy: the latest release,\n * shadowed by the child domain as `figureBlueprint` does. A type map is the board server's.\n */\n @Directive('@privilege(category: \"figure-published\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(returns => GraphQLJSON, {\n description:\n 'Released figures asked together by full name {namespace}/{type}: { items: [{ type, ref, asset }], refused: [{ type, code, message }] }. The latest release of each; one refusal never removes another item.'\n })\n async figureBlueprints(\n @Arg('types', type => [String], { description: 'Full figure names {namespace}/{type}. At most 500.' }) types: string[],\n @Ctx() context: ResolverContext\n ): Promise<any> {\n const { domain } = context.state\n const names = [...new Set(types)]\n if (names.length > FIGURE_BLUEPRINTS_MAX) {\n throw new Refusal('figure-names-too-many', { count: names.length, max: FIGURE_BLUEPRINTS_MAX }, 'at most {max} figure names can be asked at once, not {count}.')\n }\n\n const items: { type: string; ref: string; asset: unknown }[] = []\n const refused: { type: string; code: string; message: string }[] = []\n /* Plain text: a board draws the reason on a canvas, so a name with `/` is not escaped. */\n const refuse = (type: string, refusal: Refusal) =>\n refused.push({\n type,\n code: refusal.code,\n message: context.t\n ? context.t(refusalKey(refusal.code), { ...refusal.params, defaultValue: refusal.message, interpolation: { escapeValue: false } })\n : refusal.message\n })\n\n for (const type of names) {\n const name = parseFigureName(type)\n if (!name) {\n refuse(type, new Refusal('figure-name-malformed', { type }, '{type} is not a full figure name of the form namespace/type.'))\n continue\n }\n const found =\n (await releasedSourceOfName(domain.id, name)) ??\n (domain.parentId ? await releasedSourceOfName(domain.parentId, name) : null) ??\n (await publicReleasedSourceOf(name))\n if (!found) {\n refuse(type, new Refusal('figure-not-released', { type }, 'no release is published here.'))\n continue\n }\n try {\n items.push({ type, ref: formatFigureRef({ ...name, version: found.version }), asset: consumablePayloadOf(found.source).asset })\n } catch {\n refuse(\n type,\n new Refusal(\n 'figure-release-does-not-compile',\n { type, figureId: found.figure.id, version: found.version },\n 'the released source of {type} does not compile. open it in the modeller and release it again.'\n )\n )\n }\n }\n\n return { items, refused }\n }\n}\n\nconst FIGURE_BLUEPRINTS_MAX = 500\n\n/** The released source of a full name in one domain: the type there, published under that namespace. */\nasync function releasedSourceOfName(domainId: string, name: FigureName) {\n const found = await releasedSourceOf(domainId, name.type)\n return found && found.figure.namespace === name.namespace ? found : null\n}\n\n/** The released source of another domain's public figure by full name (G2): looked at after the reader's own. */\nasync function publicReleasedSourceOf(name: FigureName) {\n const figure = await publicFigureOfName(name.namespace, name.type)\n return figure?.domain ? releasedSourceOfName(figure.domain.id, name) : null\n}\n\n/** One numbered release of a figure, or null when it has none by that number. */\nasync function releaseNumbered(figure: Figure, version: number): Promise<{ figure: Figure; source: string; version: number } | null> {\n const row = await getRepository(FigureHistory).findOne({\n where: { originalId: figure.id, state: 'released', version }\n })\n return row?.source ? { figure, source: row.source, version: row.version } : null\n}\n\n/**\n * Finds the released source of a type in one domain, or null.\n *\n * A released row gives its own source; a draft row gives the source of its latest released history.\n * A figure that was never released gives null, because drafts never reach consumers.\n */\nasync function releasedSourceOf(\n domainId: string,\n type: string\n): Promise<{ figure: Figure; source: string; version: number } | null> {\n const figure = await getRepository(Figure).findOne({ where: { domain: { id: domainId }, type } })\n if (!figure) return null\n\n if (figure.state === 'released' && figure.source) {\n return { figure, source: figure.source, version: figure.version }\n }\n\n const latestReleased = await getRepository(FigureHistory).findOne({\n where: { domain: { id: domainId }, originalId: figure.id, state: 'released' },\n order: { version: 'DESC' }\n })\n\n /* The version travels with the source: a refusal names the edition that does not compile, and the\n row's own version is the draft being edited, not the one the board was handed. */\n return latestReleased?.source\n ? { figure, source: latestReleased.source, version: latestReleased.version }\n : null\n}\n"]}
@@ -26,10 +26,30 @@ export interface RenameFacts {
26
26
  hasHistory: boolean;
27
27
  /** 같은 도메인에서 그 이름을 이미 쓰는 **다른** 도형이 있나. */
28
28
  takenByAnother: boolean;
29
+ /**
30
+ * 같은 도메인에서 그 이름으로 발행한 뒤 지워진 도형이 있나. 발행한 도형을 지울 수 없게 되기(G4) 전에 지워진 것이다.
31
+ * 그 이름을 다시 쓰면 판 번호가 1부터 다시 매겨져 같은 `ns/type@n` 이 다른 내용을 가리킨다.
32
+ */
33
+ releasedBefore?: boolean;
29
34
  }
35
+ /** Whether a figure of this type was released and then deleted in the domain (deleted before G4 refused it). */
36
+ export declare function typeReleasedBefore(repositories: {
37
+ figures: {
38
+ find(options: any): Promise<{
39
+ id?: string;
40
+ }[]>;
41
+ };
42
+ histories: {
43
+ count(options: any): Promise<number>;
44
+ };
45
+ }, domain: {
46
+ id: string;
47
+ }, type: string): Promise<boolean>;
48
+ /** Said when a type was released and deleted before: a new figure may not take it. */
49
+ export declare const releasedBeforeMessage: (type: string) => string;
30
50
  export declare class FigureRenameRefused extends Error {
31
- readonly code: 'empty-type' | 'malformed-type' | 'already-released' | 'type-taken';
32
- constructor(code: 'empty-type' | 'malformed-type' | 'already-released' | 'type-taken', message: string);
51
+ readonly code: 'empty-type' | 'malformed-type' | 'already-released' | 'type-taken' | 'type-released-before';
52
+ constructor(code: 'empty-type' | 'malformed-type' | 'already-released' | 'type-taken' | 'type-released-before', message: string);
33
53
  }
34
54
  /**
35
55
  * 고친 이름과 정본. 못 고치면 **까닭과 함께 던진다** — 조용히 옛 이름으로 두지 않는다.
@@ -57,6 +77,9 @@ export declare function renameFacts(repositories: {
57
77
  findOne(options: any): Promise<{
58
78
  id?: string;
59
79
  } | null>;
80
+ find(options: any): Promise<{
81
+ id?: string;
82
+ }[]>;
60
83
  };
61
84
  histories: {
62
85
  count(options: any): Promise<number>;
@@ -1,9 +1,24 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.FigureRenameRefused = void 0;
3
+ exports.FigureRenameRefused = exports.releasedBeforeMessage = void 0;
4
+ exports.typeReleasedBefore = typeReleasedBefore;
4
5
  exports.renameDraftType = renameDraftType;
5
6
  exports.renameFacts = renameFacts;
7
+ const typeorm_1 = require("typeorm");
6
8
  const figure_model_1 = require("@hatiolab/figure-model");
9
+ /** Whether a figure of this type was released and then deleted in the domain (deleted before G4 refused it). */
10
+ async function typeReleasedBefore(repositories, domain, type) {
11
+ const deleted = await repositories.figures.find({
12
+ where: { domain: { id: domain.id }, type, deletedAt: (0, typeorm_1.Not)((0, typeorm_1.IsNull)()) },
13
+ withDeleted: true,
14
+ select: ['id']
15
+ });
16
+ const ids = deleted.map(figure => figure.id).filter(Boolean);
17
+ return ids.length > 0 && (await repositories.histories.count({ where: { originalId: (0, typeorm_1.In)(ids) } })) > 0;
18
+ }
19
+ /** Said when a type was released and deleted before: a new figure may not take it. */
20
+ const releasedBeforeMessage = (type) => `type 「${type}」 는 이 도메인에서 발행한 뒤 지운 도형의 이름이다 — 다시 쓰면 같은 판 번호가 다른 내용을 가리키므로 다른 이름을 고른다`;
21
+ exports.releasedBeforeMessage = releasedBeforeMessage;
7
22
  class FigureRenameRefused extends Error {
8
23
  constructor(code, message) {
9
24
  super(message);
@@ -36,6 +51,9 @@ function renameDraftType(current, wanted, facts) {
36
51
  if (facts.takenByAnother) {
37
52
  throw new FigureRenameRefused('type-taken', `type 「${next}」 는 이 도메인에서 이미 쓰고 있다`);
38
53
  }
54
+ if (facts.releasedBefore) {
55
+ throw new FigureRenameRefused('type-released-before', (0, exports.releasedBeforeMessage)(next));
56
+ }
39
57
  /* The asset carries no `type`: the name a board uses is the row's alone, so only the row changes. */
40
58
  return { type: next, source: current.source };
41
59
  }
@@ -51,6 +69,7 @@ async function renameFacts(repositories, figure, domain, wanted) {
51
69
  const next = wanted.trim();
52
70
  const hasHistory = (await repositories.histories.count({ where: { originalId: figure.id } })) > 0;
53
71
  const taken = next ? await repositories.figures.findOne({ where: { domain: { id: domain.id }, type: next } }) : null;
54
- return { version: figure.version, hasHistory, takenByAnother: !!taken && taken.id !== figure.id };
72
+ const releasedBefore = next ? await typeReleasedBefore(repositories, domain, next) : false;
73
+ return { version: figure.version, hasHistory, takenByAnother: !!taken && taken.id !== figure.id, releasedBefore };
55
74
  }
56
75
  //# sourceMappingURL=figure-rename.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"figure-rename.js","sourceRoot":"","sources":["../../../server/service/figure/figure-rename.ts"],"names":[],"mappings":";;;AAiDA,0CAmCC;AAUD,kCAcC;AA5GD,yDAAkE;AAiClE,MAAa,mBAAoB,SAAQ,KAAK;IAC5C,YACW,IAAyE,EAClF,OAAe;QAEf,KAAK,CAAC,OAAO,CAAC,CAAA;QAHL,SAAI,GAAJ,IAAI,CAAqE;QAIlF,IAAI,CAAC,IAAI,GAAG,qBAAqB,CAAA;IACnC,CAAC;CACF;AARD,kDAQC;AAED;;;;;GAKG;AACH,SAAgB,eAAe,CAC7B,OAAyC,EACzC,MAAc,EACd,KAAkB;IAElB,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,EAAE,CAAA;IAE1B,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,MAAM,IAAI,mBAAmB,CAAC,YAAY,EAAE,qCAAqC,CAAC,CAAA;IACpF,CAAC;IAED;;;MAGE;IACF,IAAI,CAAC,2BAAY,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,MAAM,GAAG,0BAAW,CAAC,GAAG,IAAI,IAAI,CAAC,MAAM,GAAG,0BAAW,CAAC,GAAG,EAAE,CAAC;QAC/F,MAAM,IAAI,mBAAmB,CAC3B,gBAAgB,EAChB,SAAS,IAAI,oCAAoC,0BAAW,CAAC,GAAG,IAAI,0BAAW,CAAC,GAAG,QAAQ,CAC5F,CAAA;IACH,CAAC;IAED,IAAI,CAAC,KAAK,CAAC,OAAO,IAAI,CAAC,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC,UAAU,EAAE,CAAC;QACjD,MAAM,IAAI,mBAAmB,CAC3B,kBAAkB,EAClB,gDAAgD,CACjD,CAAA;IACH,CAAC;IAED,IAAI,KAAK,CAAC,cAAc,EAAE,CAAC;QACzB,MAAM,IAAI,mBAAmB,CAAC,YAAY,EAAE,SAAS,IAAI,sBAAsB,CAAC,CAAA;IAClF,CAAC;IAED,qGAAqG;IACrG,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAA;AAC/C,CAAC;AAED;;;;;;;GAOG;AACI,KAAK,UAAU,WAAW,CAC/B,YAGC,EACD,MAAyC,EACzC,MAAsB,EACtB,MAAc;IAEd,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,EAAE,CAAA;IAC1B,MAAM,UAAU,GAAG,CAAC,MAAM,YAAY,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,EAAE,UAAU,EAAE,MAAM,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAA;IACjG,MAAM,KAAK,GAAG,IAAI,CAAC,CAAC,CAAC,MAAM,YAAY,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,MAAM,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;IAEpH,OAAO,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,CAAC,CAAC,KAAK,IAAI,KAAK,CAAC,EAAE,KAAK,MAAM,CAAC,EAAE,EAAE,CAAA;AACnG,CAAC","sourcesContent":["import { TYPE_LENGTH, TYPE_PATTERN } from '@hatiolab/figure-model'\n/**\n * 초안의 타입을 고치는 규칙 — ADR-0063 결정 4.\n *\n * ## 왜 발행 전에만인가\n *\n * `type` 은 도면에 적히는 이름이다. 도면은 `{ type, left, top, width, height }` 만 갖고 늘 최신\n * 발행판을 그리므로, 발행된 도형의 이름을 바꾸면 이미 배치된 도면이 아무 오류 없이 빈 자리가\n * 된다. 한 번도 발행되지 않은 도형은 그려질 자리가 없으니 가리키는 도면도 있을 수 없다.\n *\n * ## 왜 열어야 했나\n *\n * 닫아 두었더니 저작자가 이름을 **한 번도** 정하지 못했다. 새 Figure 에는 기계가 지은 이름이\n * 붙고(`FIGURE_MU6RJH47`) 칸에 자물쇠가 걸려서, 그 이름이 그대로 도면에 적히는 이름이 됐다.\n * 그렇게 남은 초안이 14 개다.\n *\n * ## 셈은 여기, 질의는 부르는 쪽\n *\n * 이 파일은 저장소를 모른다 — 판 번호 · 이력 유무 · 같은 이름의 주인을 **사실로 받는다.**\n * 그래야 규칙을 DB 없이 시험한다. 문(`figure-mutation.ts`)이 그 셋을 읽어 넘긴다.\n */\n\n\n/** 이름을 바꿀 때 알아야 하는 사실. 부르는 쪽이 저장소에서 읽어 온다. */\nexport interface RenameFacts {\n /** 발행 판 번호. 0 이면 한 번도 발행되지 않았다. */\n version?: number\n /** 판본이 하나라도 있나. 되돌리기로 판 번호가 도로 낮아져도 이력은 남는다. */\n hasHistory: boolean\n /** 같은 도메인에서 그 이름을 이미 쓰는 **다른** 도형이 있나. */\n takenByAnother: boolean\n}\n\nexport class FigureRenameRefused extends Error {\n constructor(\n readonly code: 'empty-type' | 'malformed-type' | 'already-released' | 'type-taken',\n message: string\n ) {\n super(message)\n this.name = 'FigureRenameRefused'\n }\n}\n\n/**\n * 고친 이름과 정본. 못 고치면 **까닭과 함께 던진다** — 조용히 옛 이름으로 두지 않는다.\n *\n * 정본 안에도 `type` 이 있어서 함께 고친다. 한쪽만 고치면 저장된 JSON 과 행이 다른 이름을\n * 말하고, 발행할 때 어느 쪽이 도면에 적히는지가 갈린다.\n */\nexport function renameDraftType(\n current: { type: string; source: string },\n wanted: string,\n facts: RenameFacts\n): { type: string; source: string } {\n const next = wanted.trim()\n\n if (!next) {\n throw new FigureRenameRefused('empty-type', 'type 이 비어 있다 — 도면에 적히는 이름이라 비울 수 없다')\n }\n\n /*\n The shape the modeller has always asked for, now asked here too (designer 2026-09-27, Q-D3): only a type being set\n is held to it -- every type in the development data already keeps it (56 of 56, 2026-09-27), and none is renamed.\n */\n if (!TYPE_PATTERN.test(next) || next.length < TYPE_LENGTH.min || next.length > TYPE_LENGTH.max) {\n throw new FigureRenameRefused(\n 'malformed-type',\n `type 「${next}」 는 소문자로 시작하고 소문자·숫자·하이픈 하나씩만 쓰며 ${TYPE_LENGTH.min}~${TYPE_LENGTH.max}자여야 한다`\n )\n }\n\n if ((facts.version ?? 0) > 0 || facts.hasHistory) {\n throw new FigureRenameRefused(\n 'already-released',\n '발행된 도형의 type 은 바꿀 수 없다 — 이미 배치된 도면이 이 이름을 가리킨다'\n )\n }\n\n if (facts.takenByAnother) {\n throw new FigureRenameRefused('type-taken', `type 「${next}」 는 이 도메인에서 이미 쓰고 있다`)\n }\n\n /* The asset carries no `type`: the name a board uses is the row's alone, so only the row changes. */\n return { type: next, source: current.source }\n}\n\n/**\n * 사실 셋을 저장소에서 읽는다.\n *\n * 규칙에서 떼어 둔 자리이지만 **질의의 모양이 틀리면 저작자에게는 저장 실패로만 보인다.**\n * 실제로 그랬다 — 판본을 `figure: { id }` 로 물었고, `FigureHistory` 는 관계 칸이 아니라\n * `originalId` 로 가리킨다. TypeORM 이 「그런 속성이 없다」로 던졌고 화면에는 영문 오류 한 줄이\n * 떴다. 그래서 이 함수를 내보내 sqlite 를 들고 왕복까지 본다.\n */\nexport async function renameFacts(\n repositories: {\n figures: { findOne(options: any): Promise<{ id?: string } | null> }\n histories: { count(options: any): Promise<number> }\n },\n figure: { id?: string; version?: number },\n domain: { id: string },\n wanted: string\n): Promise<RenameFacts> {\n const next = wanted.trim()\n const hasHistory = (await repositories.histories.count({ where: { originalId: figure.id } })) > 0\n const taken = next ? await repositories.figures.findOne({ where: { domain: { id: domain.id }, type: next } }) : null\n\n return { version: figure.version, hasHistory, takenByAnother: !!taken && taken.id !== figure.id }\n}\n"]}
1
+ {"version":3,"file":"figure-rename.js","sourceRoot":"","sources":["../../../server/service/figure/figure-rename.ts"],"names":[],"mappings":"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","sourcesContent":["import { In, IsNull, Not } from 'typeorm'\nimport { TYPE_LENGTH, TYPE_PATTERN } from '@hatiolab/figure-model'\n/**\n * 초안의 타입을 고치는 규칙 — ADR-0063 결정 4.\n *\n * ## 왜 발행 전에만인가\n *\n * `type` 은 도면에 적히는 이름이다. 도면은 `{ type, left, top, width, height }` 만 갖고 늘 최신\n * 발행판을 그리므로, 발행된 도형의 이름을 바꾸면 이미 배치된 도면이 아무 오류 없이 빈 자리가\n * 된다. 한 번도 발행되지 않은 도형은 그려질 자리가 없으니 가리키는 도면도 있을 수 없다.\n *\n * ## 왜 열어야 했나\n *\n * 닫아 두었더니 저작자가 이름을 **한 번도** 정하지 못했다. 새 Figure 에는 기계가 지은 이름이\n * 붙고(`FIGURE_MU6RJH47`) 칸에 자물쇠가 걸려서, 그 이름이 그대로 도면에 적히는 이름이 됐다.\n * 그렇게 남은 초안이 14 개다.\n *\n * ## 셈은 여기, 질의는 부르는 쪽\n *\n * 이 파일은 저장소를 모른다 — 판 번호 · 이력 유무 · 같은 이름의 주인을 **사실로 받는다.**\n * 그래야 규칙을 DB 없이 시험한다. 문(`figure-mutation.ts`)이 그 셋을 읽어 넘긴다.\n */\n\n\n/** 이름을 바꿀 때 알아야 하는 사실. 부르는 쪽이 저장소에서 읽어 온다. */\nexport interface RenameFacts {\n /** 발행 판 번호. 0 이면 한 번도 발행되지 않았다. */\n version?: number\n /** 판본이 하나라도 있나. 되돌리기로 판 번호가 도로 낮아져도 이력은 남는다. */\n hasHistory: boolean\n /** 같은 도메인에서 그 이름을 이미 쓰는 **다른** 도형이 있나. */\n takenByAnother: boolean\n /**\n * 같은 도메인에서 그 이름으로 발행한 뒤 지워진 도형이 있나. 발행한 도형을 지울 수 없게 되기(G4) 전에 지워진 것이다.\n * 그 이름을 다시 쓰면 판 번호가 1부터 다시 매겨져 같은 `ns/type@n` 이 다른 내용을 가리킨다.\n */\n releasedBefore?: boolean\n}\n\n/** Whether a figure of this type was released and then deleted in the domain (deleted before G4 refused it). */\nexport async function typeReleasedBefore(\n repositories: {\n figures: { find(options: any): Promise<{ id?: string }[]> }\n histories: { count(options: any): Promise<number> }\n },\n domain: { id: string },\n type: string\n): Promise<boolean> {\n const deleted = await repositories.figures.find({\n where: { domain: { id: domain.id }, type, deletedAt: Not(IsNull()) },\n withDeleted: true,\n select: ['id']\n })\n const ids = deleted.map(figure => figure.id).filter(Boolean)\n return ids.length > 0 && (await repositories.histories.count({ where: { originalId: In(ids) } })) > 0\n}\n\n/** Said when a type was released and deleted before: a new figure may not take it. */\nexport const releasedBeforeMessage = (type: string) =>\n `type 「${type}」 는 이 도메인에서 발행한 뒤 지운 도형의 이름이다 — 다시 쓰면 같은 판 번호가 다른 내용을 가리키므로 다른 이름을 고른다`\n\nexport class FigureRenameRefused extends Error {\n constructor(\n readonly code: 'empty-type' | 'malformed-type' | 'already-released' | 'type-taken' | 'type-released-before',\n message: string\n ) {\n super(message)\n this.name = 'FigureRenameRefused'\n }\n}\n\n/**\n * 고친 이름과 정본. 못 고치면 **까닭과 함께 던진다** — 조용히 옛 이름으로 두지 않는다.\n *\n * 정본 안에도 `type` 이 있어서 함께 고친다. 한쪽만 고치면 저장된 JSON 과 행이 다른 이름을\n * 말하고, 발행할 때 어느 쪽이 도면에 적히는지가 갈린다.\n */\nexport function renameDraftType(\n current: { type: string; source: string },\n wanted: string,\n facts: RenameFacts\n): { type: string; source: string } {\n const next = wanted.trim()\n\n if (!next) {\n throw new FigureRenameRefused('empty-type', 'type 이 비어 있다 — 도면에 적히는 이름이라 비울 수 없다')\n }\n\n /*\n The shape the modeller has always asked for, now asked here too (designer 2026-09-27, Q-D3): only a type being set\n is held to it -- every type in the development data already keeps it (56 of 56, 2026-09-27), and none is renamed.\n */\n if (!TYPE_PATTERN.test(next) || next.length < TYPE_LENGTH.min || next.length > TYPE_LENGTH.max) {\n throw new FigureRenameRefused(\n 'malformed-type',\n `type 「${next}」 는 소문자로 시작하고 소문자·숫자·하이픈 하나씩만 쓰며 ${TYPE_LENGTH.min}~${TYPE_LENGTH.max}자여야 한다`\n )\n }\n\n if ((facts.version ?? 0) > 0 || facts.hasHistory) {\n throw new FigureRenameRefused(\n 'already-released',\n '발행된 도형의 type 은 바꿀 수 없다 — 이미 배치된 도면이 이 이름을 가리킨다'\n )\n }\n\n if (facts.takenByAnother) {\n throw new FigureRenameRefused('type-taken', `type 「${next}」 는 이 도메인에서 이미 쓰고 있다`)\n }\n\n if (facts.releasedBefore) {\n throw new FigureRenameRefused('type-released-before', releasedBeforeMessage(next))\n }\n\n /* The asset carries no `type`: the name a board uses is the row's alone, so only the row changes. */\n return { type: next, source: current.source }\n}\n\n/**\n * 사실 셋을 저장소에서 읽는다.\n *\n * 규칙에서 떼어 둔 자리이지만 **질의의 모양이 틀리면 저작자에게는 저장 실패로만 보인다.**\n * 실제로 그랬다 — 판본을 `figure: { id }` 로 물었고, `FigureHistory` 는 관계 칸이 아니라\n * `originalId` 로 가리킨다. TypeORM 이 「그런 속성이 없다」로 던졌고 화면에는 영문 오류 한 줄이\n * 떴다. 그래서 이 함수를 내보내 sqlite 를 들고 왕복까지 본다.\n */\nexport async function renameFacts(\n repositories: {\n figures: { findOne(options: any): Promise<{ id?: string } | null>; find(options: any): Promise<{ id?: string }[]> }\n histories: { count(options: any): Promise<number> }\n },\n figure: { id?: string; version?: number },\n domain: { id: string },\n wanted: string\n): Promise<RenameFacts> {\n const next = wanted.trim()\n const hasHistory = (await repositories.histories.count({ where: { originalId: figure.id } })) > 0\n const taken = next ? await repositories.figures.findOne({ where: { domain: { id: domain.id }, type: next } }) : null\n\n const releasedBefore = next ? await typeReleasedBefore(repositories, domain, next) : false\n\n return { version: figure.version, hasHistory, takenByAnother: !!taken && taken.id !== figure.id, releasedBefore }\n}\n"]}
@@ -385,7 +385,7 @@ function figureToolSpecs() {
385
385
  const current = sourceForTool(row, ctx?.host);
386
386
  const { inspectSource } = getDeps();
387
387
  /* Inspected whole, here; only what the model is told is held to its budget. */
388
- return { ...findingsWithinBudget(inspectSource(current.source ? JSON.stringify(current.source) : null, null, undefined, row.type)), draft: current.draft };
388
+ return { ...findingsWithinBudget(inspectSource(current.source ? JSON.stringify(current.source) : null, null, undefined, row.type, row.category)), draft: current.draft };
389
389
  }
390
390
  },
391
391
  {