@things-factory/figure-library 10.1.218 → 10.1.222
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/dist-client/bootstrap.d.ts +5 -3
- package/dist-client/bootstrap.js +6 -3
- package/dist-client/bootstrap.js.map +1 -1
- package/dist-client/editors/ox-property-editor-figure-status.d.ts +41 -0
- package/dist-client/editors/ox-property-editor-figure-status.js +290 -0
- package/dist-client/editors/ox-property-editor-figure-status.js.map +1 -0
- package/dist-client/figure-palette-group.d.ts +9 -4
- package/dist-client/figure-palette-group.js +2 -1
- package/dist-client/figure-palette-group.js.map +1 -1
- package/dist-client/figure-palette.js +2 -1
- package/dist-client/figure-palette.js.map +1 -1
- package/dist-client/item-types/item-types-rows.d.ts +8 -0
- package/dist-client/item-types/item-types-rows.js +11 -0
- package/dist-client/item-types/item-types-rows.js.map +1 -1
- package/dist-client/item-types/ox-item-types-input.d.ts +5 -1
- package/dist-client/item-types/ox-item-types-input.js +144 -112
- package/dist-client/item-types/ox-item-types-input.js.map +1 -1
- package/dist-client/pages/figure-library-page.js +0 -1
- package/dist-client/pages/figure-library-page.js.map +1 -1
- package/dist-client/status-looks/ox-figure-status-looks.d.ts +58 -0
- package/dist-client/status-looks/ox-figure-status-looks.js +489 -0
- package/dist-client/status-looks/ox-figure-status-looks.js.map +1 -0
- package/dist-client/status-looks/status-looks.d.ts +99 -0
- package/dist-client/status-looks/status-looks.js +134 -0
- package/dist-client/status-looks/status-looks.js.map +1 -0
- package/dist-client/tsconfig.tsbuildinfo +1 -1
- package/dist-client/viewparts/figure-releases-popup.d.ts +1 -4
- package/dist-client/viewparts/figure-releases-popup.js +3 -21
- package/dist-client/viewparts/figure-releases-popup.js.map +1 -1
- package/dist-server/service/figure-library-release/figure-library-release.d.ts +3 -1
- package/dist-server/service/figure-library-release/figure-library-release.js +11 -1
- package/dist-server/service/figure-library-release/figure-library-release.js.map +1 -1
- package/dist-server/service/figure-library-resolver.d.ts +0 -1
- package/dist-server/service/figure-library-resolver.js +0 -15
- package/dist-server/service/figure-library-resolver.js.map +1 -1
- package/dist-server/service/figure-library-types.js +1 -1
- package/dist-server/service/figure-library-types.js.map +1 -1
- package/dist-server/service/figure-type-map/figure-type-map-entry.d.ts +0 -1
- package/dist-server/service/figure-type-map/figure-type-map-entry.js +1 -12
- package/dist-server/service/figure-type-map/figure-type-map-entry.js.map +1 -1
- package/dist-server/service/library/derived.d.ts +6 -2
- package/dist-server/service/library/derived.js +4 -2
- package/dist-server/service/library/derived.js.map +1 -1
- package/dist-server/service/library/figures.d.ts +2 -2
- package/dist-server/service/library/figures.js +2 -2
- package/dist-server/service/library/figures.js.map +1 -1
- package/dist-server/service/library/type-map.d.ts +0 -5
- package/dist-server/service/library/type-map.js +0 -14
- package/dist-server/service/library/type-map.js.map +1 -1
- package/dist-server/tsconfig.tsbuildinfo +1 -1
- package/package.json +5 -5
- package/translations/en.json +49 -5
- package/translations/es.json +49 -5
- package/translations/ja.json +49 -5
- package/translations/ko.json +49 -5
- package/translations/ms.json +49 -5
- package/translations/zh.json +49 -5
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/** What this server derives from a release's source: whether its kernel reads it, its authored size, its capabilities and its extension properties. */
|
|
1
|
+
/** What this server derives from a release's source: whether its kernel reads it, its authored size, its capabilities, its item tag and its extension properties. */
|
|
2
2
|
export interface DerivedOfSource {
|
|
3
3
|
formatSupported: boolean;
|
|
4
4
|
checkedKernel: string;
|
|
@@ -6,12 +6,16 @@ export interface DerivedOfSource {
|
|
|
6
6
|
depth: number | null;
|
|
7
7
|
/** The roles of the places the source declares (`document.capabilities.bindings[].role`: seat, grip), [] for none. Null when unread. */
|
|
8
8
|
capabilities: string[] | null;
|
|
9
|
+
/** Whether the source tags the figure as the look of an item (ADR-0155 amendment 2). Null when unread. */
|
|
10
|
+
item: boolean | null;
|
|
11
|
+
/** Whether the figure holds things -- capability names, places or a slot layout (`figureHoldsThings`). Null when unread. */
|
|
12
|
+
holder: boolean | null;
|
|
9
13
|
/** The extension properties the source carries, by key (ADR-0123 결정 5), as the source has them. Null when none or unread. */
|
|
10
14
|
extensions: Record<string, unknown> | null;
|
|
11
15
|
}
|
|
12
16
|
/**
|
|
13
17
|
* Reads a source with this server's kernel. A source it cannot read is kept (ADR-0114 결정 5) and marked; the size,
|
|
14
|
-
* the capabilities and the extension properties are then unknown, never guessed.
|
|
18
|
+
* the capabilities, the item tag and the extension properties are then unknown, never guessed.
|
|
15
19
|
*/
|
|
16
20
|
export declare function derivedOfSource(source: string): DerivedOfSource;
|
|
17
21
|
/** Whether a row's derived values were made by another kernel than this server's and must be made again. */
|
|
@@ -5,7 +5,7 @@ exports.derivedIsStale = derivedIsStale;
|
|
|
5
5
|
const figure_model_1 = require("@hatiolab/figure-model");
|
|
6
6
|
/**
|
|
7
7
|
* Reads a source with this server's kernel. A source it cannot read is kept (ADR-0114 결정 5) and marked; the size,
|
|
8
|
-
* the capabilities and the extension properties are then unknown, never guessed.
|
|
8
|
+
* the capabilities, the item tag and the extension properties are then unknown, never guessed.
|
|
9
9
|
*/
|
|
10
10
|
function derivedOfSource(source) {
|
|
11
11
|
try {
|
|
@@ -18,11 +18,13 @@ function derivedOfSource(source) {
|
|
|
18
18
|
width,
|
|
19
19
|
depth,
|
|
20
20
|
capabilities: [...new Set(asset.document.capabilities.bindings.map(binding => binding.role))].sort(),
|
|
21
|
+
item: asset.item === true,
|
|
22
|
+
holder: (0, figure_model_1.figureHoldsThings)(asset),
|
|
21
23
|
extensions: asset.extensions ? structuredClone(asset.extensions) : null
|
|
22
24
|
};
|
|
23
25
|
}
|
|
24
26
|
catch {
|
|
25
|
-
return { formatSupported: false, checkedKernel: figure_model_1.FIGURE_KERNEL_VERSION, width: null, depth: null, capabilities: null, extensions: null };
|
|
27
|
+
return { formatSupported: false, checkedKernel: figure_model_1.FIGURE_KERNEL_VERSION, width: null, depth: null, capabilities: null, item: null, holder: null, extensions: null };
|
|
26
28
|
}
|
|
27
29
|
}
|
|
28
30
|
/** Whether a row's derived values were made by another kernel than this server's and must be made again. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"derived.js","sourceRoot":"","sources":["../../../server/service/library/derived.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"derived.js","sourceRoot":"","sources":["../../../server/service/library/derived.ts"],"names":[],"mappings":"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","sourcesContent":["import { compileFigureAsset, FIGURE_KERNEL_VERSION, FIGURE_SIZE_INPUTS, figureHoldsThings, figureTopViewOf, parseFigureAsset, type FigureAsset } from '@hatiolab/figure-model'\n\n/** What this server derives from a release's source: whether its kernel reads it, its authored size, its capabilities, its item tag and its extension properties. */\nexport interface DerivedOfSource {\n formatSupported: boolean\n checkedKernel: string\n width: number | null\n depth: number | null\n /** The roles of the places the source declares (`document.capabilities.bindings[].role`: seat, grip), [] for none. Null when unread. */\n capabilities: string[] | null\n /** Whether the source tags the figure as the look of an item (ADR-0155 amendment 2). Null when unread. */\n item: boolean | null\n /** Whether the figure holds things -- capability names, places or a slot layout (`figureHoldsThings`). Null when unread. */\n holder: boolean | null\n /** The extension properties the source carries, by key (ADR-0123 결정 5), as the source has them. Null when none or unread. */\n extensions: Record<string, unknown> | null\n}\n\n/**\n * Reads a source with this server's kernel. A source it cannot read is kept (ADR-0114 결정 5) and marked; the size,\n * the capabilities, the item tag and the extension properties are then unknown, never guessed.\n */\nexport function derivedOfSource(source: string): DerivedOfSource {\n try {\n const asset = parseFigureAsset(source)\n compileFigureAsset(asset)\n const { width, depth } = authoredPlanOf(asset)\n return {\n formatSupported: true,\n checkedKernel: FIGURE_KERNEL_VERSION,\n width,\n depth,\n capabilities: [...new Set(asset.document.capabilities.bindings.map(binding => binding.role))].sort(),\n item: asset.item === true,\n holder: figureHoldsThings(asset),\n extensions: asset.extensions ? structuredClone(asset.extensions) : null\n }\n } catch {\n return { formatSupported: false, checkedKernel: FIGURE_KERNEL_VERSION, width: null, depth: null, capabilities: null, item: null, holder: null, extensions: null }\n }\n}\n\n/** Whether a row's derived values were made by another kernel than this server's and must be made again. */\nexport function derivedIsStale(row: { checkedKernel?: string | null }): boolean {\n return row.checkedKernel !== FIGURE_KERNEL_VERSION\n}\n\n/**\n * The plan size a figure is placed at: its size inputs when it declares them (what the scene scales against), else the\n * extent of its top view at the authored size.\n */\nfunction authoredPlanOf(asset: FigureAsset): { width: number | null; depth: number | null } {\n const input = (axis: 'x' | 'z') => {\n const value = asset.designInputs?.[FIGURE_SIZE_INPUTS[axis]]\n return typeof value === 'number' && Number.isFinite(value) && value > 0 ? value : null\n }\n const width = input('x')\n const depth = input('z')\n if (width !== null && depth !== null) return { width, depth }\n\n const points = figureTopViewOf(asset, null).shapes.flatMap(shape => shape.outline)\n if (!points.length) return { width: null, depth: null }\n const span = (i: 0 | 1) => Math.max(...points.map(p => p[i])) - Math.min(...points.map(p => p[i]))\n const round = (value: number) => (value > 0 ? Math.round(value * 1000) / 1000 : null)\n return { width: width ?? round(span(0)), depth: depth ?? round(span(1)) }\n}\n"]}
|
|
@@ -14,7 +14,7 @@ export interface FiguresQuery {
|
|
|
14
14
|
search?: string;
|
|
15
15
|
/** Archived names (ADR-0114 결정 18) are left out unless this is true. */
|
|
16
16
|
includeArchived?: boolean;
|
|
17
|
-
/** Only the names
|
|
17
|
+
/** Only the names whose release in use is tagged as an item (ADR-0155 amendment 2). */
|
|
18
18
|
onlyItems?: boolean;
|
|
19
19
|
page?: number;
|
|
20
20
|
limit?: number;
|
|
@@ -29,7 +29,7 @@ export interface FigureOfLibrary {
|
|
|
29
29
|
releaseCount: number;
|
|
30
30
|
/** When the name was archived; null while in use. */
|
|
31
31
|
archivedAt: Date | null;
|
|
32
|
-
/** Whether
|
|
32
|
+
/** Whether the release in use is tagged as an item, the look of a thing a holder holds. */
|
|
33
33
|
item: boolean;
|
|
34
34
|
}
|
|
35
35
|
/**
|
|
@@ -25,7 +25,7 @@ async function figuresOf(tx, domain, query) {
|
|
|
25
25
|
if (!query.includeArchived)
|
|
26
26
|
builder.andWhere('line.archived_at IS NULL');
|
|
27
27
|
if (query.onlyItems)
|
|
28
|
-
builder.andWhere('
|
|
28
|
+
builder.andWhere('release.item = :item', { item: true });
|
|
29
29
|
if (query.category === exports.FIGURE_FILTER_NONE)
|
|
30
30
|
builder.andWhere(`(release.category IS NULL OR release.category = '')`);
|
|
31
31
|
else if (query.category)
|
|
@@ -63,7 +63,7 @@ async function figuresOf(tx, domain, query) {
|
|
|
63
63
|
items: lines.map(line => {
|
|
64
64
|
const all = byName.get(line.name) ?? [];
|
|
65
65
|
const latest = all[0] ?? line.release;
|
|
66
|
-
return { name: line.name, release: line.release ?? null, latest, latestVersion: latest.version, releaseCount: all.length, archivedAt: line.archivedAt ?? null, item: !!line.item };
|
|
66
|
+
return { name: line.name, release: line.release ?? null, latest, latestVersion: latest.version, releaseCount: all.length, archivedAt: line.archivedAt ?? null, item: !!line.release?.item };
|
|
67
67
|
})
|
|
68
68
|
};
|
|
69
69
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"figures.js","sourceRoot":"","sources":["../../../server/service/library/figures.ts"],"names":[],"mappings":"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","sourcesContent":["import { Brackets, EntityManager } from 'typeorm'\n\nimport { FigureLibraryRelease } from '../figure-library-release/figure-library-release'\nimport { FigureTypeMapEntry } from '../figure-type-map/figure-type-map-entry'\nimport { fullNameOf } from './type-map'\n\ntype Domain = { id: string }\n\n/** The filter value for a figure with no category, or one that declares no capability. */\nexport const FIGURE_FILTER_NONE = '-'\n\nexport interface FiguresQuery {\n /** A category, or FIGURE_FILTER_NONE for figures without one. */\n category?: string\n /** A place role (seat, grip), or FIGURE_FILTER_NONE for figures that declare no place. */\n capability?: string\n /** Part of the full name or the display name. */\n search?: string\n /** Archived names (ADR-0114 결정 18) are left out unless this is true. */\n includeArchived?: boolean\n /** Only the names this domain draws as items (ADR-0155 개정 1 E). */\n onlyItems?: boolean\n page?: number\n limit?: number\n}\n\nexport interface FigureOfLibrary {\n name: string\n /** The release in use; null when none of its releases can be drawn here. */\n release: FigureLibraryRelease | null\n /** The newest release imported, drawable or not. */\n latest: FigureLibraryRelease\n latestVersion: number\n releaseCount: number\n /** When the name was archived; null while in use. */\n archivedAt: Date | null\n /** Whether this domain draws the name as an item a holder holds. */\n item: boolean\n}\n\n/**\n * The library by figure (ADR-0114, amended 2026-10-12): one item per full name with the release it draws with, its\n * latest release and how many releases are imported. Filters and paging run in the database, so a library of thousands\n * pages like any list. Category and capability are those of the release that draws; a figure with none in use has\n * neither.\n */\nexport async function figuresOf(tx: EntityManager, domain: Domain, query: FiguresQuery): Promise<{ items: FigureOfLibrary[]; total: number }> {\n const builder = tx\n .getRepository(FigureTypeMapEntry)\n .createQueryBuilder('line')\n .leftJoinAndSelect('line.release', 'release')\n .where('line.domain_id = :domain', { domain: domain.id })\n\n if (!query.includeArchived) builder.andWhere('line.archived_at IS NULL')\n if (query.onlyItems) builder.andWhere('line.item = :item', { item: true })\n\n if (query.category === FIGURE_FILTER_NONE) builder.andWhere(`(release.category IS NULL OR release.category = '')`)\n else if (query.category) builder.andWhere('release.category = :category', { category: query.category })\n\n /* `capabilities` is a JSON list of roles; a role is matched with its quotes so one never matches inside another. */\n if (query.capability === FIGURE_FILTER_NONE) builder.andWhere(`release.capabilities = '[]'`)\n else if (query.capability) builder.andWhere('release.capabilities LIKE :capability', { capability: `%\"${query.capability}\"%` })\n\n if (query.search) {\n const search = `%${query.search.toLowerCase()}%`\n builder.andWhere(new Brackets(where => where.where('LOWER(line.name) LIKE :search', { search }).orWhere('LOWER(release.name) LIKE :search', { search })))\n }\n\n const limit = Math.max(1, Math.min(query.limit ?? 50, 500))\n const page = Math.max(1, query.page ?? 1)\n const [lines, total] = await builder\n .orderBy('line.name', 'ASC')\n .skip((page - 1) * limit)\n .take(limit)\n .getManyAndCount()\n\n const releases = lines.length\n ? await tx.getRepository(FigureLibraryRelease).find({\n where: lines.map(line => {\n const slash = line.name.indexOf('/')\n return { domain: { id: domain.id }, namespace: line.name.slice(0, slash), type: line.name.slice(slash + 1) }\n }),\n order: { version: 'DESC' }\n })\n : []\n const byName = new Map<string, FigureLibraryRelease[]>()\n for (const release of releases) byName.set(fullNameOf(release), [...(byName.get(fullNameOf(release)) ?? []), release])\n\n return {\n total,\n items: lines.map(line => {\n const all = byName.get(line.name) ?? []\n const latest = all[0] ?? line.release!\n return { name: line.name, release: line.release ?? null, latest, latestVersion: latest.version, releaseCount: all.length, archivedAt: line.archivedAt ?? null, item: !!line.item }\n })\n }\n}\n\n/** What the filters offer: the categories and place roles of the releases that draw, and whether any has none. */\nexport async function figureFacetsOf(tx: EntityManager, domain: Domain) {\n const lines = await tx.getRepository(FigureTypeMapEntry).find({\n where: { domain: { id: domain.id } },\n relations: { release: true },\n select: { id: true, release: { id: true, category: true, capabilities: true } }\n })\n const drawn = lines.map(line => line.release).filter(Boolean) as FigureLibraryRelease[]\n return {\n categories: [...new Set(drawn.map(release => release.category).filter(Boolean) as string[])].sort(),\n uncategorized: drawn.some(release => !release.category),\n capabilities: [...new Set(drawn.flatMap(release => release.capabilities ?? []))].sort(),\n incapable: drawn.some(release => Array.isArray(release.capabilities) && release.capabilities.length === 0)\n }\n}\n\n/** Every imported release of one full name, newest first. */\nexport async function releasesOfName(tx: EntityManager, domain: Domain, name: string): Promise<FigureLibraryRelease[]> {\n const slash = name.indexOf('/')\n if (slash < 0) return []\n return await tx.getRepository(FigureLibraryRelease).find({\n where: { domain: { id: domain.id }, namespace: name.slice(0, slash), type: name.slice(slash + 1) },\n order: { version: 'DESC' }\n })\n}\n"]}
|
|
1
|
+
{"version":3,"file":"figures.js","sourceRoot":"","sources":["../../../server/service/library/figures.ts"],"names":[],"mappings":"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","sourcesContent":["import { Brackets, EntityManager } from 'typeorm'\n\nimport { FigureLibraryRelease } from '../figure-library-release/figure-library-release'\nimport { FigureTypeMapEntry } from '../figure-type-map/figure-type-map-entry'\nimport { fullNameOf } from './type-map'\n\ntype Domain = { id: string }\n\n/** The filter value for a figure with no category, or one that declares no capability. */\nexport const FIGURE_FILTER_NONE = '-'\n\nexport interface FiguresQuery {\n /** A category, or FIGURE_FILTER_NONE for figures without one. */\n category?: string\n /** A place role (seat, grip), or FIGURE_FILTER_NONE for figures that declare no place. */\n capability?: string\n /** Part of the full name or the display name. */\n search?: string\n /** Archived names (ADR-0114 결정 18) are left out unless this is true. */\n includeArchived?: boolean\n /** Only the names whose release in use is tagged as an item (ADR-0155 amendment 2). */\n onlyItems?: boolean\n page?: number\n limit?: number\n}\n\nexport interface FigureOfLibrary {\n name: string\n /** The release in use; null when none of its releases can be drawn here. */\n release: FigureLibraryRelease | null\n /** The newest release imported, drawable or not. */\n latest: FigureLibraryRelease\n latestVersion: number\n releaseCount: number\n /** When the name was archived; null while in use. */\n archivedAt: Date | null\n /** Whether the release in use is tagged as an item, the look of a thing a holder holds. */\n item: boolean\n}\n\n/**\n * The library by figure (ADR-0114, amended 2026-10-12): one item per full name with the release it draws with, its\n * latest release and how many releases are imported. Filters and paging run in the database, so a library of thousands\n * pages like any list. Category and capability are those of the release that draws; a figure with none in use has\n * neither.\n */\nexport async function figuresOf(tx: EntityManager, domain: Domain, query: FiguresQuery): Promise<{ items: FigureOfLibrary[]; total: number }> {\n const builder = tx\n .getRepository(FigureTypeMapEntry)\n .createQueryBuilder('line')\n .leftJoinAndSelect('line.release', 'release')\n .where('line.domain_id = :domain', { domain: domain.id })\n\n if (!query.includeArchived) builder.andWhere('line.archived_at IS NULL')\n if (query.onlyItems) builder.andWhere('release.item = :item', { item: true })\n\n if (query.category === FIGURE_FILTER_NONE) builder.andWhere(`(release.category IS NULL OR release.category = '')`)\n else if (query.category) builder.andWhere('release.category = :category', { category: query.category })\n\n /* `capabilities` is a JSON list of roles; a role is matched with its quotes so one never matches inside another. */\n if (query.capability === FIGURE_FILTER_NONE) builder.andWhere(`release.capabilities = '[]'`)\n else if (query.capability) builder.andWhere('release.capabilities LIKE :capability', { capability: `%\"${query.capability}\"%` })\n\n if (query.search) {\n const search = `%${query.search.toLowerCase()}%`\n builder.andWhere(new Brackets(where => where.where('LOWER(line.name) LIKE :search', { search }).orWhere('LOWER(release.name) LIKE :search', { search })))\n }\n\n const limit = Math.max(1, Math.min(query.limit ?? 50, 500))\n const page = Math.max(1, query.page ?? 1)\n const [lines, total] = await builder\n .orderBy('line.name', 'ASC')\n .skip((page - 1) * limit)\n .take(limit)\n .getManyAndCount()\n\n const releases = lines.length\n ? await tx.getRepository(FigureLibraryRelease).find({\n where: lines.map(line => {\n const slash = line.name.indexOf('/')\n return { domain: { id: domain.id }, namespace: line.name.slice(0, slash), type: line.name.slice(slash + 1) }\n }),\n order: { version: 'DESC' }\n })\n : []\n const byName = new Map<string, FigureLibraryRelease[]>()\n for (const release of releases) byName.set(fullNameOf(release), [...(byName.get(fullNameOf(release)) ?? []), release])\n\n return {\n total,\n items: lines.map(line => {\n const all = byName.get(line.name) ?? []\n const latest = all[0] ?? line.release!\n return { name: line.name, release: line.release ?? null, latest, latestVersion: latest.version, releaseCount: all.length, archivedAt: line.archivedAt ?? null, item: !!line.release?.item }\n })\n }\n}\n\n/** What the filters offer: the categories and place roles of the releases that draw, and whether any has none. */\nexport async function figureFacetsOf(tx: EntityManager, domain: Domain) {\n const lines = await tx.getRepository(FigureTypeMapEntry).find({\n where: { domain: { id: domain.id } },\n relations: { release: true },\n select: { id: true, release: { id: true, category: true, capabilities: true } }\n })\n const drawn = lines.map(line => line.release).filter(Boolean) as FigureLibraryRelease[]\n return {\n categories: [...new Set(drawn.map(release => release.category).filter(Boolean) as string[])].sort(),\n uncategorized: drawn.some(release => !release.category),\n capabilities: [...new Set(drawn.flatMap(release => release.capabilities ?? []))].sort(),\n incapable: drawn.some(release => Array.isArray(release.capabilities) && release.capabilities.length === 0)\n }\n}\n\n/** Every imported release of one full name, newest first. */\nexport async function releasesOfName(tx: EntityManager, domain: Domain, name: string): Promise<FigureLibraryRelease[]> {\n const slash = name.indexOf('/')\n if (slash < 0) return []\n return await tx.getRepository(FigureLibraryRelease).find({\n where: { domain: { id: domain.id }, namespace: name.slice(0, slash), type: name.slice(slash + 1) },\n order: { version: 'DESC' }\n })\n}\n"]}
|
|
@@ -28,11 +28,6 @@ export declare function putIntoTypeMap(tx: EntityManager, domain: Domain, user:
|
|
|
28
28
|
* archived name changes nothing.
|
|
29
29
|
*/
|
|
30
30
|
export declare function archiveFigure(tx: EntityManager, domain: Domain, user: unknown, name: string): Promise<FigureTypeMapEntry>;
|
|
31
|
-
/**
|
|
32
|
-
* Marks `name` as an item this domain draws -- a carrier in fmsim -- or takes the mark away (ADR-0155 개정 1 E). The
|
|
33
|
-
* mark is the line's: a newer release of the name keeps it. Marking it as it is changes nothing.
|
|
34
|
-
*/
|
|
35
|
-
export declare function markFigureItem(tx: EntityManager, domain: Domain, user: unknown, name: string, item: boolean): Promise<FigureTypeMapEntry>;
|
|
36
31
|
/** Brings an archived name back (ADR-0114 결정 20), drawing with the release its line kept. Unarchiving one in use changes nothing. */
|
|
37
32
|
export declare function unarchiveFigure(tx: EntityManager, domain: Domain, user: unknown, name: string): Promise<FigureTypeMapEntry>;
|
|
38
33
|
export {};
|
|
@@ -6,7 +6,6 @@ exports.inUseLinesOf = inUseLinesOf;
|
|
|
6
6
|
exports.chooseRelease = chooseRelease;
|
|
7
7
|
exports.putIntoTypeMap = putIntoTypeMap;
|
|
8
8
|
exports.archiveFigure = archiveFigure;
|
|
9
|
-
exports.markFigureItem = markFigureItem;
|
|
10
9
|
exports.unarchiveFigure = unarchiveFigure;
|
|
11
10
|
const figure_model_1 = require("@hatiolab/figure-model");
|
|
12
11
|
const board_service_1 = require("@things-factory/board-service");
|
|
@@ -102,19 +101,6 @@ async function archiveFigure(tx, domain, user, name) {
|
|
|
102
101
|
await tx.getRepository(figure_type_map_entry_1.FigureTypeMapEntry).update({ id: line.id }, { archivedAt: new Date(), archivedBy: user, updater: user });
|
|
103
102
|
return (await lineOf(tx, domain, name));
|
|
104
103
|
}
|
|
105
|
-
/**
|
|
106
|
-
* Marks `name` as an item this domain draws -- a carrier in fmsim -- or takes the mark away (ADR-0155 개정 1 E). The
|
|
107
|
-
* mark is the line's: a newer release of the name keeps it. Marking it as it is changes nothing.
|
|
108
|
-
*/
|
|
109
|
-
async function markFigureItem(tx, domain, user, name, item) {
|
|
110
|
-
const line = await lineOf(tx, domain, name);
|
|
111
|
-
if (!line)
|
|
112
|
-
throw new shell_1.Refusal('figure-not-in-type-map', { type: name }, 'not in the type map of this domain.');
|
|
113
|
-
if (!!line.item === item)
|
|
114
|
-
return line;
|
|
115
|
-
await tx.getRepository(figure_type_map_entry_1.FigureTypeMapEntry).update({ id: line.id }, { item, updater: user });
|
|
116
|
-
return (await lineOf(tx, domain, name));
|
|
117
|
-
}
|
|
118
104
|
/** Brings an archived name back (ADR-0114 결정 20), drawing with the release its line kept. Unarchiving one in use changes nothing. */
|
|
119
105
|
async function unarchiveFigure(tx, domain, user, name) {
|
|
120
106
|
const line = await lineOf(tx, domain, name);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"type-map.js","sourceRoot":"","sources":["../../../server/service/library/type-map.ts"],"names":[],"mappings":"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","sourcesContent":["import { EntityManager } from 'typeorm'\n\nimport { formatFigureName } from '@hatiolab/figure-model'\nimport { Board } from '@things-factory/board-service'\nimport { Refusal } from '@things-factory/shell'\n\nimport { FigureLibraryRelease } from '../figure-library-release/figure-library-release'\nimport { FigureTypeMapEntry } from '../figure-type-map/figure-type-map-entry'\nimport { figureNodesOf } from './board-walk'\n\ntype Domain = { id: string }\n\n/** The full name a release is the release of. */\nexport const fullNameOf = (release: Pick<FigureLibraryRelease, 'namespace' | 'type'>) =>\n formatFigureName({ namespace: release.namespace, type: release.type })\n\n/** The domain's type map: one line per full name, with the release it draws with. */\nexport function linesOf(tx: EntityManager, domain: Domain): Promise<FigureTypeMapEntry[]> {\n return tx.getRepository(FigureTypeMapEntry).find({ where: { domain: { id: domain.id } }, relations: { release: true }, order: { name: 'ASC' } })\n}\n\n/** The lines a board may draw from: the type map without its archived names (ADR-0114 결정 18) -- what the tray offers. */\nexport async function inUseLinesOf(tx: EntityManager, domain: Domain): Promise<FigureTypeMapEntry[]> {\n return (await linesOf(tx, domain)).filter(line => !line.archivedAt)\n}\n\nfunction lineOf(tx: EntityManager, domain: Domain, name: string): Promise<FigureTypeMapEntry | null> {\n return tx.getRepository(FigureTypeMapEntry).findOne({ where: { domain: { id: domain.id }, name }, relations: { release: true } })\n}\n\n/**\n * Makes `releaseId` the release `name` draws with (ADR-0114 결정 15): a release of this domain's library, and the\n * release of that very name. Refused by the first fault, named.\n */\nexport async function chooseRelease(tx: EntityManager, domain: Domain, user: unknown, name: string, releaseId: string): Promise<FigureTypeMapEntry> {\n const release = await tx.getRepository(FigureLibraryRelease).findOne({ where: { id: releaseId } })\n if (!release) {\n throw new Refusal('figure-type-map-missing-release', { name }, 'the release chosen for {name} is not in the library.')\n }\n if (release.domainId !== domain.id) {\n throw new Refusal('figure-type-map-foreign-release', { name }, 'the release chosen for {name} belongs to another domain.')\n }\n if (fullNameOf(release) !== name) {\n throw new Refusal('figure-type-map-name-mismatch', { name, ref: release.ref }, '{ref} is not a release of {name}.')\n }\n if (!release.formatSupported) {\n throw new Refusal('figure-type-map-format-unsupported', { name, ref: release.ref }, '{ref} is in a format this server cannot draw.')\n }\n return await setLine(tx, domain, user, name, release)\n}\n\n/**\n * What an import does to the type map (ADR-0114 결정 7, amended 2026-10-12): the newest release this server can draw is\n * the one in use. A release of a name the map does not have adds its line; a drawable release newer than the one a line\n * draws with moves the line to it; an older one leaves it. A release in a format this server cannot read never takes\n * over: a name that has only such releases keeps a line with no release, so it is listed and boards are told why.\n */\nexport async function putIntoTypeMap(tx: EntityManager, domain: Domain, user: unknown, release: FigureLibraryRelease): Promise<void> {\n const name = fullNameOf(release)\n const line = await lineOf(tx, domain, name)\n if (!release.formatSupported) {\n if (!line) await setLine(tx, domain, user, name, null)\n return\n }\n if (line?.release && line.release.version >= release.version) return\n await setLine(tx, domain, user, name, release)\n}\n\nasync function setLine(tx: EntityManager, domain: Domain, user: unknown, name: string, release: FigureLibraryRelease | null): Promise<FigureTypeMapEntry> {\n const repository = tx.getRepository(FigureTypeMapEntry)\n const line = await lineOf(tx, domain, name)\n const target = release ? { id: release.id } : null\n if (line) await repository.update({ id: line.id }, { release: target, updater: user } as any)\n else await repository.save({ domain, name, release: target, creator: user, updater: user } as Partial<FigureTypeMapEntry>)\n return (await lineOf(tx, domain, name))!\n}\n\n/** How many boards a refusal names before it says how many more there are. */\nconst BOARDS_NAMED = 5\n\n/** The boards of this domain that hold a node of `name`, by board name. */\nasync function boardsUsing(tx: EntityManager, domain: Domain, name: string): Promise<string[]> {\n const boards = await tx.getRepository(Board).find({ where: { domain: { id: domain.id } }, select: { id: true, name: true, model: true } })\n return boards.filter(board => figureNodesOf(board.model).has(name)).map(board => board.name ?? board.id)\n}\n\n/**\n * Archives `name` (ADR-0114 결정 18 · 19, 2026-10-22): the line and its releases stay, the name leaves the tray, the type\n * map and the batch door. Refused while a board of this domain holds a node of it, naming those boards. Archiving a\n * archived name changes nothing.\n */\nexport async function archiveFigure(tx: EntityManager, domain: Domain, user: unknown, name: string): Promise<FigureTypeMapEntry> {\n const line = await lineOf(tx, domain, name)\n if (!line) throw new Refusal('figure-not-in-type-map', { type: name }, 'not in the type map of this domain.')\n if (line.archivedAt) return line\n const boards = await boardsUsing(tx, domain, name)\n if (boards.length) {\n const shown = boards.slice(0, BOARDS_NAMED).join(', ') + (boards.length > BOARDS_NAMED ? ` +${boards.length - BOARDS_NAMED}` : '')\n throw new Refusal('figure-in-use', { name, count: boards.length, boards: shown }, '{name} is on {count} board(s): {boards}. Take it off them first.')\n }\n await tx.getRepository(FigureTypeMapEntry).update({ id: line.id }, { archivedAt: new Date(), archivedBy: user, updater: user } as any)\n return (await lineOf(tx, domain, name))!\n}\n\n/**\n * Marks `name` as an item this domain draws -- a carrier in fmsim -- or takes the mark away (ADR-0155 개정 1 E). The\n * mark is the line's: a newer release of the name keeps it. Marking it as it is changes nothing.\n */\nexport async function markFigureItem(tx: EntityManager, domain: Domain, user: unknown, name: string, item: boolean): Promise<FigureTypeMapEntry> {\n const line = await lineOf(tx, domain, name)\n if (!line) throw new Refusal('figure-not-in-type-map', { type: name }, 'not in the type map of this domain.')\n if (!!line.item === item) return line\n await tx.getRepository(FigureTypeMapEntry).update({ id: line.id }, { item, updater: user } as any)\n return (await lineOf(tx, domain, name))!\n}\n\n/** Brings an archived name back (ADR-0114 결정 20), drawing with the release its line kept. Unarchiving one in use changes nothing. */\nexport async function unarchiveFigure(tx: EntityManager, domain: Domain, user: unknown, name: string): Promise<FigureTypeMapEntry> {\n const line = await lineOf(tx, domain, name)\n if (!line) throw new Refusal('figure-not-in-type-map', { type: name }, 'not in the type map of this domain.')\n if (!line.archivedAt) return line\n await tx.getRepository(FigureTypeMapEntry).update({ id: line.id }, { archivedAt: null, archivedBy: null, updater: user } as any)\n return (await lineOf(tx, domain, name))!\n}\n"]}
|
|
1
|
+
{"version":3,"file":"type-map.js","sourceRoot":"","sources":["../../../server/service/library/type-map.ts"],"names":[],"mappings":"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","sourcesContent":["import { EntityManager } from 'typeorm'\n\nimport { formatFigureName } from '@hatiolab/figure-model'\nimport { Board } from '@things-factory/board-service'\nimport { Refusal } from '@things-factory/shell'\n\nimport { FigureLibraryRelease } from '../figure-library-release/figure-library-release'\nimport { FigureTypeMapEntry } from '../figure-type-map/figure-type-map-entry'\nimport { figureNodesOf } from './board-walk'\n\ntype Domain = { id: string }\n\n/** The full name a release is the release of. */\nexport const fullNameOf = (release: Pick<FigureLibraryRelease, 'namespace' | 'type'>) =>\n formatFigureName({ namespace: release.namespace, type: release.type })\n\n/** The domain's type map: one line per full name, with the release it draws with. */\nexport function linesOf(tx: EntityManager, domain: Domain): Promise<FigureTypeMapEntry[]> {\n return tx.getRepository(FigureTypeMapEntry).find({ where: { domain: { id: domain.id } }, relations: { release: true }, order: { name: 'ASC' } })\n}\n\n/** The lines a board may draw from: the type map without its archived names (ADR-0114 결정 18) -- what the tray offers. */\nexport async function inUseLinesOf(tx: EntityManager, domain: Domain): Promise<FigureTypeMapEntry[]> {\n return (await linesOf(tx, domain)).filter(line => !line.archivedAt)\n}\n\nfunction lineOf(tx: EntityManager, domain: Domain, name: string): Promise<FigureTypeMapEntry | null> {\n return tx.getRepository(FigureTypeMapEntry).findOne({ where: { domain: { id: domain.id }, name }, relations: { release: true } })\n}\n\n/**\n * Makes `releaseId` the release `name` draws with (ADR-0114 결정 15): a release of this domain's library, and the\n * release of that very name. Refused by the first fault, named.\n */\nexport async function chooseRelease(tx: EntityManager, domain: Domain, user: unknown, name: string, releaseId: string): Promise<FigureTypeMapEntry> {\n const release = await tx.getRepository(FigureLibraryRelease).findOne({ where: { id: releaseId } })\n if (!release) {\n throw new Refusal('figure-type-map-missing-release', { name }, 'the release chosen for {name} is not in the library.')\n }\n if (release.domainId !== domain.id) {\n throw new Refusal('figure-type-map-foreign-release', { name }, 'the release chosen for {name} belongs to another domain.')\n }\n if (fullNameOf(release) !== name) {\n throw new Refusal('figure-type-map-name-mismatch', { name, ref: release.ref }, '{ref} is not a release of {name}.')\n }\n if (!release.formatSupported) {\n throw new Refusal('figure-type-map-format-unsupported', { name, ref: release.ref }, '{ref} is in a format this server cannot draw.')\n }\n return await setLine(tx, domain, user, name, release)\n}\n\n/**\n * What an import does to the type map (ADR-0114 결정 7, amended 2026-10-12): the newest release this server can draw is\n * the one in use. A release of a name the map does not have adds its line; a drawable release newer than the one a line\n * draws with moves the line to it; an older one leaves it. A release in a format this server cannot read never takes\n * over: a name that has only such releases keeps a line with no release, so it is listed and boards are told why.\n */\nexport async function putIntoTypeMap(tx: EntityManager, domain: Domain, user: unknown, release: FigureLibraryRelease): Promise<void> {\n const name = fullNameOf(release)\n const line = await lineOf(tx, domain, name)\n if (!release.formatSupported) {\n if (!line) await setLine(tx, domain, user, name, null)\n return\n }\n if (line?.release && line.release.version >= release.version) return\n await setLine(tx, domain, user, name, release)\n}\n\nasync function setLine(tx: EntityManager, domain: Domain, user: unknown, name: string, release: FigureLibraryRelease | null): Promise<FigureTypeMapEntry> {\n const repository = tx.getRepository(FigureTypeMapEntry)\n const line = await lineOf(tx, domain, name)\n const target = release ? { id: release.id } : null\n if (line) await repository.update({ id: line.id }, { release: target, updater: user } as any)\n else await repository.save({ domain, name, release: target, creator: user, updater: user } as Partial<FigureTypeMapEntry>)\n return (await lineOf(tx, domain, name))!\n}\n\n/** How many boards a refusal names before it says how many more there are. */\nconst BOARDS_NAMED = 5\n\n/** The boards of this domain that hold a node of `name`, by board name. */\nasync function boardsUsing(tx: EntityManager, domain: Domain, name: string): Promise<string[]> {\n const boards = await tx.getRepository(Board).find({ where: { domain: { id: domain.id } }, select: { id: true, name: true, model: true } })\n return boards.filter(board => figureNodesOf(board.model).has(name)).map(board => board.name ?? board.id)\n}\n\n/**\n * Archives `name` (ADR-0114 결정 18 · 19, 2026-10-22): the line and its releases stay, the name leaves the tray, the type\n * map and the batch door. Refused while a board of this domain holds a node of it, naming those boards. Archiving a\n * archived name changes nothing.\n */\nexport async function archiveFigure(tx: EntityManager, domain: Domain, user: unknown, name: string): Promise<FigureTypeMapEntry> {\n const line = await lineOf(tx, domain, name)\n if (!line) throw new Refusal('figure-not-in-type-map', { type: name }, 'not in the type map of this domain.')\n if (line.archivedAt) return line\n const boards = await boardsUsing(tx, domain, name)\n if (boards.length) {\n const shown = boards.slice(0, BOARDS_NAMED).join(', ') + (boards.length > BOARDS_NAMED ? ` +${boards.length - BOARDS_NAMED}` : '')\n throw new Refusal('figure-in-use', { name, count: boards.length, boards: shown }, '{name} is on {count} board(s): {boards}. Take it off them first.')\n }\n await tx.getRepository(FigureTypeMapEntry).update({ id: line.id }, { archivedAt: new Date(), archivedBy: user, updater: user } as any)\n return (await lineOf(tx, domain, name))!\n}\n\n/** Brings an archived name back (ADR-0114 결정 20), drawing with the release its line kept. Unarchiving one in use changes nothing. */\nexport async function unarchiveFigure(tx: EntityManager, domain: Domain, user: unknown, name: string): Promise<FigureTypeMapEntry> {\n const line = await lineOf(tx, domain, name)\n if (!line) throw new Refusal('figure-not-in-type-map', { type: name }, 'not in the type map of this domain.')\n if (!line.archivedAt) return line\n await tx.getRepository(FigureTypeMapEntry).update({ id: line.id }, { archivedAt: null, archivedBy: null, updater: user } as any)\n return (await lineOf(tx, domain, name))!\n}\n"]}
|