@things-factory/figure-service 10.1.68 → 10.1.70
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-server/index.js +14 -0
- package/dist-server/index.js.map +1 -1
- package/dist-server/service/figure-recipe/figure-recipe-resolver.d.ts +7 -0
- package/dist-server/service/figure-recipe/figure-recipe-resolver.js +66 -0
- package/dist-server/service/figure-recipe/figure-recipe-resolver.js.map +1 -0
- package/dist-server/service/figure-recipe/figure-recipe-store.d.ts +41 -0
- package/dist-server/service/figure-recipe/figure-recipe-store.js +105 -0
- package/dist-server/service/figure-recipe/figure-recipe-store.js.map +1 -0
- package/dist-server/service/figure-recipe/figure-recipe.d.ts +19 -0
- package/dist-server/service/figure-recipe/figure-recipe.js +67 -0
- package/dist-server/service/figure-recipe/figure-recipe.js.map +1 -0
- package/dist-server/service/figure-recipe/index.d.ts +4 -0
- package/dist-server/service/figure-recipe/index.js +8 -0
- package/dist-server/service/figure-recipe/index.js.map +1 -0
- package/dist-server/service/index.d.ts +4 -2
- package/dist-server/service/index.js +10 -3
- package/dist-server/service/index.js.map +1 -1
- package/dist-server/tsconfig.tsbuildinfo +1 -1
- package/package.json +3 -3
- package/server/index.ts +14 -0
- package/server/service/figure-recipe/figure-recipe-db.test.ts +123 -0
- package/server/service/figure-recipe/figure-recipe-resolver.ts +42 -0
- package/server/service/figure-recipe/figure-recipe-store.ts +101 -0
- package/server/service/figure-recipe/figure-recipe.ts +51 -0
- package/server/service/figure-recipe/index.ts +5 -0
- package/server/service/index.ts +5 -2
package/dist-server/index.js
CHANGED
|
@@ -12,6 +12,20 @@ require("./routes.js");
|
|
|
12
12
|
*/
|
|
13
13
|
const figure_tools_js_1 = require("./service/figure/figure-tools.js");
|
|
14
14
|
(0, figure_tools_js_1.registerFigureToolCategories)();
|
|
15
|
+
/*
|
|
16
|
+
* The built-in recipes into the system domain, as auth-base fills its privileges: once, and again gives the same result
|
|
17
|
+
* (ADR-0095 condition 2). A recipe that fails its check is said here, not half put in.
|
|
18
|
+
*/
|
|
19
|
+
const figure_recipe_store_js_1 = require("./service/figure-recipe/figure-recipe-store.js");
|
|
20
|
+
process.on('bootstrap-module-start', async () => {
|
|
21
|
+
try {
|
|
22
|
+
const { added, skipped, refused } = await (0, figure_recipe_store_js_1.seedBuiltInRecipes)();
|
|
23
|
+
console.log(`[figure-service:bootstrap] recipes added ${added.length}, already there ${skipped.length}${refused.length ? `, refused: ${refused.join(' | ')}` : ''}`);
|
|
24
|
+
}
|
|
25
|
+
catch (error) {
|
|
26
|
+
console.error('[figure-service:bootstrap] recipes were not seeded:', error);
|
|
27
|
+
}
|
|
28
|
+
});
|
|
15
29
|
tslib_1.__exportStar(require("./service/index.js"), exports);
|
|
16
30
|
tslib_1.__exportStar(require("./migrations/index.js"), exports);
|
|
17
31
|
var figure_tools_js_2 = require("./service/figure/figure-tools.js");
|
package/dist-server/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../server/index.ts"],"names":[],"mappings":";;;;AAAA,uBAAoB;AAEpB;;;;;;GAMG;AACH,sEAA+E;AAC/E,IAAA,8CAA4B,GAAE,CAAA;AAE9B,6DAAkC;AAClC,gEAAqC;AACrC,oEAA+E;AAAtE,+HAAA,4BAA4B,OAAA","sourcesContent":["import './routes.js'\n\n/*\n * 저작 도구를 어시스턴트 레지스트리에 등록한다.\n *\n * 이 패키지가 적재되면 대화면(도크)이 저작 중인 Figure 의 정본·비용·발행 판정을 읽고 후보를\n * 요청할 수 있다. 능력을 복제하지 않고 figure-service 가 이미 가진 진입점을 투영한다 —\n * 노출 범위는 대화면이 `toolCategories` 로 고른다(twin-ai · board-import 와 같은 방식).\n */\nimport { registerFigureToolCategories } from './service/figure/figure-tools.js'\nregisterFigureToolCategories()\n\nexport * from './service/index.js'\nexport * from './migrations/index.js'\nexport { registerFigureToolCategories } from './service/figure/figure-tools.js'\n"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../server/index.ts"],"names":[],"mappings":";;;;AAAA,uBAAoB;AAEpB;;;;;;GAMG;AACH,sEAA+E;AAC/E,IAAA,8CAA4B,GAAE,CAAA;AAE9B;;;GAGG;AACH,2FAAmF;AACnF,OAAO,CAAC,EAAE,CAAC,wBAA+B,EAAE,KAAK,IAAI,EAAE;IACrD,IAAI,CAAC;QACH,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,MAAM,IAAA,2CAAkB,GAAE,CAAA;QAC9D,OAAO,CAAC,GAAG,CAAC,4CAA4C,KAAK,CAAC,MAAM,mBAAmB,OAAO,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,cAAc,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAA;IACtK,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,qDAAqD,EAAE,KAAK,CAAC,CAAA;IAC7E,CAAC;AACH,CAAC,CAAC,CAAA;AAEF,6DAAkC;AAClC,gEAAqC;AACrC,oEAA+E;AAAtE,+HAAA,4BAA4B,OAAA","sourcesContent":["import './routes.js'\n\n/*\n * 저작 도구를 어시스턴트 레지스트리에 등록한다.\n *\n * 이 패키지가 적재되면 대화면(도크)이 저작 중인 Figure 의 정본·비용·발행 판정을 읽고 후보를\n * 요청할 수 있다. 능력을 복제하지 않고 figure-service 가 이미 가진 진입점을 투영한다 —\n * 노출 범위는 대화면이 `toolCategories` 로 고른다(twin-ai · board-import 와 같은 방식).\n */\nimport { registerFigureToolCategories } from './service/figure/figure-tools.js'\nregisterFigureToolCategories()\n\n/*\n * The built-in recipes into the system domain, as auth-base fills its privileges: once, and again gives the same result\n * (ADR-0095 condition 2). A recipe that fails its check is said here, not half put in.\n */\nimport { seedBuiltInRecipes } from './service/figure-recipe/figure-recipe-store.js'\nprocess.on('bootstrap-module-start' as any, async () => {\n try {\n const { added, skipped, refused } = await seedBuiltInRecipes()\n console.log(`[figure-service:bootstrap] recipes added ${added.length}, already there ${skipped.length}${refused.length ? `, refused: ${refused.join(' | ')}` : ''}`)\n } catch (error) {\n console.error('[figure-service:bootstrap] recipes were not seeded:', error)\n }\n})\n\nexport * from './service/index.js'\nexport * from './migrations/index.js'\nexport { registerFigureToolCategories } from './service/figure/figure-tools.js'\n"]}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { FigureRecipe } from './figure-recipe.js';
|
|
2
|
+
export declare class FigureRecipeResolver {
|
|
3
|
+
figureRecipes(all: boolean, context: ResolverContext): Promise<FigureRecipe[]>;
|
|
4
|
+
saveFigureRecipe(source: string, state: string, context: ResolverContext): Promise<FigureRecipe>;
|
|
5
|
+
setFigureRecipeState(name: string, state: string, context: ResolverContext): Promise<FigureRecipe>;
|
|
6
|
+
deleteFigureRecipe(name: string, context: ResolverContext): Promise<boolean>;
|
|
7
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.FigureRecipeResolver = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const type_graphql_1 = require("type-graphql");
|
|
6
|
+
const shell_1 = require("@things-factory/shell");
|
|
7
|
+
const figure_recipe_js_1 = require("./figure-recipe.js");
|
|
8
|
+
const figure_recipe_store_js_1 = require("./figure-recipe-store.js");
|
|
9
|
+
let FigureRecipeResolver = class FigureRecipeResolver {
|
|
10
|
+
async figureRecipes(all, context) {
|
|
11
|
+
return await (0, figure_recipe_store_js_1.recipesFor)(context.state.domain, all ? undefined : 'released');
|
|
12
|
+
}
|
|
13
|
+
async saveFigureRecipe(source, state, context) {
|
|
14
|
+
return await (0, figure_recipe_store_js_1.saveRecipe)(context.state.domain, source, state === 'draft' ? 'draft' : 'released');
|
|
15
|
+
}
|
|
16
|
+
async setFigureRecipeState(name, state, context) {
|
|
17
|
+
return await (0, figure_recipe_store_js_1.setRecipeState)(context.state.domain, name, state === 'draft' ? 'draft' : 'released');
|
|
18
|
+
}
|
|
19
|
+
async deleteFigureRecipe(name, context) {
|
|
20
|
+
return await (0, figure_recipe_store_js_1.deleteRecipe)(context.state.domain, name);
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
exports.FigureRecipeResolver = FigureRecipeResolver;
|
|
24
|
+
tslib_1.__decorate([
|
|
25
|
+
(0, type_graphql_1.Directive)('@privilege(category: "figure", privilege: "query", domainOwnerGranted: true)'),
|
|
26
|
+
(0, type_graphql_1.Query)(returns => [figure_recipe_js_1.FigureRecipe], { description: "The recipes this domain sees: its own and its parent's (its own stand in by name). Released ones unless all is asked." }),
|
|
27
|
+
tslib_1.__param(0, (0, type_graphql_1.Arg)('all', { nullable: true, description: 'Drafts as well.' })),
|
|
28
|
+
tslib_1.__param(1, (0, type_graphql_1.Ctx)()),
|
|
29
|
+
tslib_1.__metadata("design:type", Function),
|
|
30
|
+
tslib_1.__metadata("design:paramtypes", [Boolean, Object]),
|
|
31
|
+
tslib_1.__metadata("design:returntype", Promise)
|
|
32
|
+
], FigureRecipeResolver.prototype, "figureRecipes", null);
|
|
33
|
+
tslib_1.__decorate([
|
|
34
|
+
(0, type_graphql_1.Directive)('@privilege(category: "figure", privilege: "mutation", domainOwnerGranted: true)'),
|
|
35
|
+
(0, type_graphql_1.Mutation)(returns => figure_recipe_js_1.FigureRecipe, { description: 'Saves a recipe into this domain by its name, after putting it into an empty room with its defaults (ADR-0095).' }),
|
|
36
|
+
tslib_1.__param(0, (0, type_graphql_1.Arg)('source', { description: 'The recipe JSON (figure-model V3Recipe).' })),
|
|
37
|
+
tslib_1.__param(1, (0, type_graphql_1.Arg)('state', { nullable: true, description: "'draft' or 'released' (the default)." })),
|
|
38
|
+
tslib_1.__param(2, (0, type_graphql_1.Ctx)()),
|
|
39
|
+
tslib_1.__metadata("design:type", Function),
|
|
40
|
+
tslib_1.__metadata("design:paramtypes", [String, String, Object]),
|
|
41
|
+
tslib_1.__metadata("design:returntype", Promise)
|
|
42
|
+
], FigureRecipeResolver.prototype, "saveFigureRecipe", null);
|
|
43
|
+
tslib_1.__decorate([
|
|
44
|
+
(0, type_graphql_1.Directive)('@privilege(category: "figure", privilege: "mutation", domainOwnerGranted: true)'),
|
|
45
|
+
(0, type_graphql_1.Mutation)(returns => figure_recipe_js_1.FigureRecipe, { description: "Releases a recipe of this domain's own, or takes it back to draft. A parent's recipe is copied in to be changed." }),
|
|
46
|
+
tslib_1.__param(0, (0, type_graphql_1.Arg)('name', { description: 'The recipe name.' })),
|
|
47
|
+
tslib_1.__param(1, (0, type_graphql_1.Arg)('state', { description: "'draft' or 'released'." })),
|
|
48
|
+
tslib_1.__param(2, (0, type_graphql_1.Ctx)()),
|
|
49
|
+
tslib_1.__metadata("design:type", Function),
|
|
50
|
+
tslib_1.__metadata("design:paramtypes", [String, String, Object]),
|
|
51
|
+
tslib_1.__metadata("design:returntype", Promise)
|
|
52
|
+
], FigureRecipeResolver.prototype, "setFigureRecipeState", null);
|
|
53
|
+
tslib_1.__decorate([
|
|
54
|
+
(0, type_graphql_1.Directive)('@privilege(category: "figure", privilege: "mutation", domainOwnerGranted: true)'),
|
|
55
|
+
(0, type_graphql_1.Mutation)(returns => Boolean, { description: "Deletes a recipe of this domain's own. Figures it was put into keep their parts." }),
|
|
56
|
+
tslib_1.__param(0, (0, type_graphql_1.Arg)('name', { description: 'The recipe name.' })),
|
|
57
|
+
tslib_1.__param(1, (0, type_graphql_1.Ctx)()),
|
|
58
|
+
tslib_1.__metadata("design:type", Function),
|
|
59
|
+
tslib_1.__metadata("design:paramtypes", [String, Object]),
|
|
60
|
+
tslib_1.__metadata("design:returntype", Promise)
|
|
61
|
+
], FigureRecipeResolver.prototype, "deleteFigureRecipe", null);
|
|
62
|
+
exports.FigureRecipeResolver = FigureRecipeResolver = tslib_1.__decorate([
|
|
63
|
+
(0, type_graphql_1.Resolver)(figure_recipe_js_1.FigureRecipe),
|
|
64
|
+
(0, type_graphql_1.UseMiddleware)(shell_1.SpeakRefusals)
|
|
65
|
+
], FigureRecipeResolver);
|
|
66
|
+
//# sourceMappingURL=figure-recipe-resolver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"figure-recipe-resolver.js","sourceRoot":"","sources":["../../../server/service/figure-recipe/figure-recipe-resolver.ts"],"names":[],"mappings":"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","sourcesContent":["import { Arg, Ctx, Directive, Mutation, Query, Resolver, UseMiddleware } from 'type-graphql'\n\nimport { SpeakRefusals } from '@things-factory/shell'\n\nimport { FigureRecipe } from './figure-recipe.js'\nimport { deleteRecipe, recipesFor, saveRecipe, setRecipeState } from './figure-recipe-store.js'\n\n@Resolver(FigureRecipe)\n@UseMiddleware(SpeakRefusals)\nexport class FigureRecipeResolver {\n @Directive('@privilege(category: \"figure\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(returns => [FigureRecipe], { description: \"The recipes this domain sees: its own and its parent's (its own stand in by name). Released ones unless all is asked.\" })\n async figureRecipes(@Arg('all', { nullable: true, description: 'Drafts as well.' }) all: boolean, @Ctx() context: ResolverContext): Promise<FigureRecipe[]> {\n return await recipesFor(context.state.domain, all ? undefined : 'released')\n }\n\n @Directive('@privilege(category: \"figure\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Mutation(returns => FigureRecipe, { description: 'Saves a recipe into this domain by its name, after putting it into an empty room with its defaults (ADR-0095).' })\n async saveFigureRecipe(\n @Arg('source', { description: 'The recipe JSON (figure-model V3Recipe).' }) source: string,\n @Arg('state', { nullable: true, description: \"'draft' or 'released' (the default).\" }) state: string,\n @Ctx() context: ResolverContext\n ): Promise<FigureRecipe> {\n return await saveRecipe(context.state.domain, source, state === 'draft' ? 'draft' : 'released')\n }\n\n @Directive('@privilege(category: \"figure\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Mutation(returns => FigureRecipe, { description: \"Releases a recipe of this domain's own, or takes it back to draft. A parent's recipe is copied in to be changed.\" })\n async setFigureRecipeState(\n @Arg('name', { description: 'The recipe name.' }) name: string,\n @Arg('state', { description: \"'draft' or 'released'.\" }) state: string,\n @Ctx() context: ResolverContext\n ): Promise<FigureRecipe> {\n return await setRecipeState(context.state.domain, name, state === 'draft' ? 'draft' : 'released')\n }\n\n @Directive('@privilege(category: \"figure\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Mutation(returns => Boolean, { description: \"Deletes a recipe of this domain's own. Figures it was put into keep their parts.\" })\n async deleteFigureRecipe(@Arg('name', { description: 'The recipe name.' }) name: string, @Ctx() context: ResolverContext): Promise<boolean> {\n return await deleteRecipe(context.state.domain, name)\n }\n}\n"]}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { Domain } from '@things-factory/shell';
|
|
2
|
+
import { FigureRecipe } from './figure-recipe.js';
|
|
3
|
+
/**
|
|
4
|
+
* The recipes a domain sees (ADR-0095 condition 2): its own and its parent's, as figures are read. A recipe of the
|
|
5
|
+
* domain's own stands in for the parent's of the same name.
|
|
6
|
+
*/
|
|
7
|
+
export declare function recipesFor(domain: {
|
|
8
|
+
id: string;
|
|
9
|
+
parentId?: string | null;
|
|
10
|
+
}, state?: 'released'): Promise<FigureRecipe[]>;
|
|
11
|
+
/**
|
|
12
|
+
* A recipe saved into a domain, by its name: checked first by putting it into the test room with its defaults
|
|
13
|
+
* (figure-model `checkV3Recipe`). Refused, it is not saved and the kernel's sentence goes back as it is.
|
|
14
|
+
*/
|
|
15
|
+
export declare function saveRecipe(domain: Domain, source: unknown, state?: 'draft' | 'released'): Promise<FigureRecipe>;
|
|
16
|
+
/** Released or back to draft: only released recipes are offered in the modeller. */
|
|
17
|
+
export declare function setRecipeState(domain: {
|
|
18
|
+
id: string;
|
|
19
|
+
}, name: string, state: 'draft' | 'released'): Promise<FigureRecipe>;
|
|
20
|
+
/**
|
|
21
|
+
* A recipe of the domain's own taken away. Figures it was put into keep their parts -- nothing ties them to it
|
|
22
|
+
* (ADR-0095). Where the parent has one by that name, the parent's is seen again.
|
|
23
|
+
*/
|
|
24
|
+
export declare function deleteRecipe(domain: {
|
|
25
|
+
id: string;
|
|
26
|
+
}, name: string): Promise<boolean>;
|
|
27
|
+
/** The recipes figure-model ships (`recipes/*.json`), as they are. */
|
|
28
|
+
export declare function builtInRecipes(): Array<{
|
|
29
|
+
name: string;
|
|
30
|
+
source: string;
|
|
31
|
+
}>;
|
|
32
|
+
/**
|
|
33
|
+
* The built-in recipes put into the system domain (ADR-0095 condition 2): once, and again gives the same result -- a
|
|
34
|
+
* recipe already there by name is skipped, not overwritten, so a system recipe someone changed stays as they left it.
|
|
35
|
+
* Each is checked as a saved one is; one that fails is left out and said, not half put in.
|
|
36
|
+
*/
|
|
37
|
+
export declare function seedBuiltInRecipes(): Promise<{
|
|
38
|
+
added: string[];
|
|
39
|
+
skipped: string[];
|
|
40
|
+
refused: string[];
|
|
41
|
+
}>;
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.recipesFor = recipesFor;
|
|
4
|
+
exports.saveRecipe = saveRecipe;
|
|
5
|
+
exports.setRecipeState = setRecipeState;
|
|
6
|
+
exports.deleteRecipe = deleteRecipe;
|
|
7
|
+
exports.builtInRecipes = builtInRecipes;
|
|
8
|
+
exports.seedBuiltInRecipes = seedBuiltInRecipes;
|
|
9
|
+
const fs_1 = require("fs");
|
|
10
|
+
const path_1 = require("path");
|
|
11
|
+
const typeorm_1 = require("typeorm");
|
|
12
|
+
const figure_model_1 = require("@hatiolab/figure-model");
|
|
13
|
+
const shell_1 = require("@things-factory/shell");
|
|
14
|
+
const figure_recipe_js_1 = require("./figure-recipe.js");
|
|
15
|
+
/**
|
|
16
|
+
* The recipes a domain sees (ADR-0095 condition 2): its own and its parent's, as figures are read. A recipe of the
|
|
17
|
+
* domain's own stands in for the parent's of the same name.
|
|
18
|
+
*/
|
|
19
|
+
async function recipesFor(domain, state) {
|
|
20
|
+
const ids = [domain.id, domain.parentId].filter(Boolean);
|
|
21
|
+
const rows = await (0, shell_1.getRepository)(figure_recipe_js_1.FigureRecipe).find({
|
|
22
|
+
where: { domain: { id: (0, typeorm_1.In)(ids) }, ...(state ? { state } : {}) },
|
|
23
|
+
relations: ['domain'],
|
|
24
|
+
order: { name: 'ASC' }
|
|
25
|
+
});
|
|
26
|
+
const byName = new Map();
|
|
27
|
+
for (const row of rows) {
|
|
28
|
+
const mine = row.domainId === domain.id || row.domain?.id === domain.id;
|
|
29
|
+
if (mine || !byName.has(row.name))
|
|
30
|
+
byName.set(row.name, row);
|
|
31
|
+
}
|
|
32
|
+
return [...byName.values()];
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* A recipe saved into a domain, by its name: checked first by putting it into the test room with its defaults
|
|
36
|
+
* (figure-model `checkV3Recipe`). Refused, it is not saved and the kernel's sentence goes back as it is.
|
|
37
|
+
*/
|
|
38
|
+
async function saveRecipe(domain, source, state = 'released') {
|
|
39
|
+
const recipe = (0, figure_model_1.checkV3Recipe)(typeof source === 'string' ? JSON.parse(source) : source);
|
|
40
|
+
const repository = (0, shell_1.getRepository)(figure_recipe_js_1.FigureRecipe);
|
|
41
|
+
const existing = await repository.findOne({ where: { domain: { id: domain.id }, name: recipe.name } });
|
|
42
|
+
return await repository.save({ ...(existing ?? {}), domain, name: recipe.name, source: JSON.stringify(recipe), state });
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* A recipe of the domain's own, by name. A parent's recipe is not the domain's to change: it is copied in under the same
|
|
46
|
+
* name (`saveRecipe`), and the copy stands in for it.
|
|
47
|
+
*/
|
|
48
|
+
async function ownRecipe(domain, name) {
|
|
49
|
+
const row = await (0, shell_1.getRepository)(figure_recipe_js_1.FigureRecipe).findOne({ where: { domain: { id: domain.id }, name } });
|
|
50
|
+
if (!row)
|
|
51
|
+
throw new Error(`${name} is not a recipe of this domain; a parent's recipe is copied here to be changed`);
|
|
52
|
+
return row;
|
|
53
|
+
}
|
|
54
|
+
/** Released or back to draft: only released recipes are offered in the modeller. */
|
|
55
|
+
async function setRecipeState(domain, name, state) {
|
|
56
|
+
const row = await ownRecipe(domain, name);
|
|
57
|
+
return await (0, shell_1.getRepository)(figure_recipe_js_1.FigureRecipe).save({ ...row, state });
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* A recipe of the domain's own taken away. Figures it was put into keep their parts -- nothing ties them to it
|
|
61
|
+
* (ADR-0095). Where the parent has one by that name, the parent's is seen again.
|
|
62
|
+
*/
|
|
63
|
+
async function deleteRecipe(domain, name) {
|
|
64
|
+
const row = await ownRecipe(domain, name);
|
|
65
|
+
await (0, shell_1.getRepository)(figure_recipe_js_1.FigureRecipe).softRemove(row);
|
|
66
|
+
return true;
|
|
67
|
+
}
|
|
68
|
+
/** The recipes figure-model ships (`recipes/*.json`), as they are. */
|
|
69
|
+
function builtInRecipes() {
|
|
70
|
+
const dir = (0, path_1.join)((0, path_1.dirname)(require.resolve('@hatiolab/figure-model/package.json')), 'recipes');
|
|
71
|
+
return (0, fs_1.readdirSync)(dir)
|
|
72
|
+
.filter(file => file.endsWith('.json'))
|
|
73
|
+
.sort()
|
|
74
|
+
.map(file => {
|
|
75
|
+
const source = (0, fs_1.readFileSync)((0, path_1.join)(dir, file), 'utf-8');
|
|
76
|
+
return { name: JSON.parse(source).name, source };
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* The built-in recipes put into the system domain (ADR-0095 condition 2): once, and again gives the same result -- a
|
|
81
|
+
* recipe already there by name is skipped, not overwritten, so a system recipe someone changed stays as they left it.
|
|
82
|
+
* Each is checked as a saved one is; one that fails is left out and said, not half put in.
|
|
83
|
+
*/
|
|
84
|
+
async function seedBuiltInRecipes() {
|
|
85
|
+
const system = await (0, shell_1.getRepository)(shell_1.Domain).findOne({ where: { systemFlag: true } });
|
|
86
|
+
const result = { added: [], skipped: [], refused: [] };
|
|
87
|
+
if (!system)
|
|
88
|
+
return result;
|
|
89
|
+
const repository = (0, shell_1.getRepository)(figure_recipe_js_1.FigureRecipe);
|
|
90
|
+
for (const { name, source } of builtInRecipes()) {
|
|
91
|
+
if (await repository.count({ where: { domain: { id: system.id }, name } })) {
|
|
92
|
+
result.skipped.push(name);
|
|
93
|
+
continue;
|
|
94
|
+
}
|
|
95
|
+
try {
|
|
96
|
+
await saveRecipe(system, source);
|
|
97
|
+
result.added.push(name);
|
|
98
|
+
}
|
|
99
|
+
catch (error) {
|
|
100
|
+
result.refused.push(`${name}: ${error instanceof Error ? error.message : String(error)}`);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
return result;
|
|
104
|
+
}
|
|
105
|
+
//# sourceMappingURL=figure-recipe-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"figure-recipe-store.js","sourceRoot":"","sources":["../../../server/service/figure-recipe/figure-recipe-store.ts"],"names":[],"mappings":"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","sourcesContent":["import { readdirSync, readFileSync } from 'fs'\nimport { dirname, join } from 'path'\nimport { In } from 'typeorm'\n\nimport { checkV3Recipe } from '@hatiolab/figure-model'\nimport { Domain, getRepository } from '@things-factory/shell'\n\nimport { FigureRecipe } from './figure-recipe.js'\n\n/**\n * The recipes a domain sees (ADR-0095 condition 2): its own and its parent's, as figures are read. A recipe of the\n * domain's own stands in for the parent's of the same name.\n */\nexport async function recipesFor(domain: { id: string; parentId?: string | null }, state?: 'released'): Promise<FigureRecipe[]> {\n const ids = [domain.id, domain.parentId].filter(Boolean) as string[]\n const rows = await getRepository(FigureRecipe).find({\n where: { domain: { id: In(ids) }, ...(state ? { state } : {}) },\n relations: ['domain'],\n order: { name: 'ASC' }\n })\n const byName = new Map<string, FigureRecipe>()\n for (const row of rows) {\n const mine = row.domainId === domain.id || (row.domain as Domain | undefined)?.id === domain.id\n if (mine || !byName.has(row.name!)) byName.set(row.name!, row)\n }\n return [...byName.values()]\n}\n\n/**\n * A recipe saved into a domain, by its name: checked first by putting it into the test room with its defaults\n * (figure-model `checkV3Recipe`). Refused, it is not saved and the kernel's sentence goes back as it is.\n */\nexport async function saveRecipe(domain: Domain, source: unknown, state: 'draft' | 'released' = 'released'): Promise<FigureRecipe> {\n const recipe = checkV3Recipe(typeof source === 'string' ? JSON.parse(source) : source)\n const repository = getRepository(FigureRecipe)\n const existing = await repository.findOne({ where: { domain: { id: domain.id }, name: recipe.name } })\n return await repository.save({ ...(existing ?? {}), domain, name: recipe.name, source: JSON.stringify(recipe), state })\n}\n\n/**\n * A recipe of the domain's own, by name. A parent's recipe is not the domain's to change: it is copied in under the same\n * name (`saveRecipe`), and the copy stands in for it.\n */\nasync function ownRecipe(domain: { id: string }, name: string): Promise<FigureRecipe> {\n const row = await getRepository(FigureRecipe).findOne({ where: { domain: { id: domain.id }, name } })\n if (!row) throw new Error(`${name} is not a recipe of this domain; a parent's recipe is copied here to be changed`)\n return row\n}\n\n/** Released or back to draft: only released recipes are offered in the modeller. */\nexport async function setRecipeState(domain: { id: string }, name: string, state: 'draft' | 'released'): Promise<FigureRecipe> {\n const row = await ownRecipe(domain, name)\n return await getRepository(FigureRecipe).save({ ...row, state })\n}\n\n/**\n * A recipe of the domain's own taken away. Figures it was put into keep their parts -- nothing ties them to it\n * (ADR-0095). Where the parent has one by that name, the parent's is seen again.\n */\nexport async function deleteRecipe(domain: { id: string }, name: string): Promise<boolean> {\n const row = await ownRecipe(domain, name)\n await getRepository(FigureRecipe).softRemove(row)\n return true\n}\n\n/** The recipes figure-model ships (`recipes/*.json`), as they are. */\nexport function builtInRecipes(): Array<{ name: string; source: string }> {\n const dir = join(dirname(require.resolve('@hatiolab/figure-model/package.json')), 'recipes')\n return readdirSync(dir)\n .filter(file => file.endsWith('.json'))\n .sort()\n .map(file => {\n const source = readFileSync(join(dir, file), 'utf-8')\n return { name: JSON.parse(source).name, source }\n })\n}\n\n/**\n * The built-in recipes put into the system domain (ADR-0095 condition 2): once, and again gives the same result -- a\n * recipe already there by name is skipped, not overwritten, so a system recipe someone changed stays as they left it.\n * Each is checked as a saved one is; one that fails is left out and said, not half put in.\n */\nexport async function seedBuiltInRecipes(): Promise<{ added: string[]; skipped: string[]; refused: string[] }> {\n const system = await getRepository(Domain).findOne({ where: { systemFlag: true } })\n const result = { added: [] as string[], skipped: [] as string[], refused: [] as string[] }\n if (!system) return result\n const repository = getRepository(FigureRecipe)\n for (const { name, source } of builtInRecipes()) {\n if (await repository.count({ where: { domain: { id: system.id }, name } })) {\n result.skipped.push(name)\n continue\n }\n try {\n await saveRecipe(system, source)\n result.added.push(name)\n } catch (error) {\n result.refused.push(`${name}: ${error instanceof Error ? error.message : String(error)}`)\n }\n }\n return result\n}\n"]}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Domain } from '@things-factory/shell';
|
|
2
|
+
/**
|
|
3
|
+
* FigureRecipe — 조각 하나(ADR-0095).
|
|
4
|
+
*
|
|
5
|
+
* 조각은 매개변수가 붙은 제안 명령 목록이다. 형식은 `@hatiolab/figure-model` 의 `V3Recipe` 가 정하고, 여기에는
|
|
6
|
+
* 그 원본을 통째로 담는다 — Figure 가 자산을 `source` 로 담는 것과 같다. 매개변수 · 명령을 컬럼으로 두지 않는다.
|
|
7
|
+
* 넣은 뒤의 부품은 조각과 이어지지 않으므로, 이 행을 고치거나 지워도 도형은 바뀌지 않는다.
|
|
8
|
+
*/
|
|
9
|
+
export declare class FigureRecipe {
|
|
10
|
+
readonly id?: string;
|
|
11
|
+
domain?: Domain;
|
|
12
|
+
domainId?: string;
|
|
13
|
+
name?: string;
|
|
14
|
+
source?: string;
|
|
15
|
+
state?: 'draft' | 'released';
|
|
16
|
+
createdAt?: Date;
|
|
17
|
+
updatedAt?: Date;
|
|
18
|
+
deletedAt?: Date;
|
|
19
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.FigureRecipe = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const typeorm_1 = require("typeorm");
|
|
6
|
+
const type_graphql_1 = require("type-graphql");
|
|
7
|
+
const shell_1 = require("@things-factory/shell");
|
|
8
|
+
/**
|
|
9
|
+
* FigureRecipe — 조각 하나(ADR-0095).
|
|
10
|
+
*
|
|
11
|
+
* 조각은 매개변수가 붙은 제안 명령 목록이다. 형식은 `@hatiolab/figure-model` 의 `V3Recipe` 가 정하고, 여기에는
|
|
12
|
+
* 그 원본을 통째로 담는다 — Figure 가 자산을 `source` 로 담는 것과 같다. 매개변수 · 명령을 컬럼으로 두지 않는다.
|
|
13
|
+
* 넣은 뒤의 부품은 조각과 이어지지 않으므로, 이 행을 고치거나 지워도 도형은 바뀌지 않는다.
|
|
14
|
+
*/
|
|
15
|
+
let FigureRecipe = class FigureRecipe {
|
|
16
|
+
};
|
|
17
|
+
exports.FigureRecipe = FigureRecipe;
|
|
18
|
+
tslib_1.__decorate([
|
|
19
|
+
(0, typeorm_1.PrimaryGeneratedColumn)('uuid'),
|
|
20
|
+
(0, type_graphql_1.Field)(type => type_graphql_1.ID, { nullable: true, description: 'Unique identifier for the recipe.' }),
|
|
21
|
+
tslib_1.__metadata("design:type", String)
|
|
22
|
+
], FigureRecipe.prototype, "id", void 0);
|
|
23
|
+
tslib_1.__decorate([
|
|
24
|
+
(0, typeorm_1.ManyToOne)(type => shell_1.Domain),
|
|
25
|
+
(0, type_graphql_1.Field)(type => shell_1.Domain, { nullable: true, description: 'The domain this recipe belongs to.' }),
|
|
26
|
+
tslib_1.__metadata("design:type", shell_1.Domain)
|
|
27
|
+
], FigureRecipe.prototype, "domain", void 0);
|
|
28
|
+
tslib_1.__decorate([
|
|
29
|
+
(0, typeorm_1.RelationId)((recipe) => recipe.domain),
|
|
30
|
+
tslib_1.__metadata("design:type", String)
|
|
31
|
+
], FigureRecipe.prototype, "domainId", void 0);
|
|
32
|
+
tslib_1.__decorate([
|
|
33
|
+
(0, typeorm_1.Column)(),
|
|
34
|
+
(0, type_graphql_1.Field)({ description: 'The recipe name, unique per domain: lower case, digits and hyphens.' }),
|
|
35
|
+
tslib_1.__metadata("design:type", String)
|
|
36
|
+
], FigureRecipe.prototype, "name", void 0);
|
|
37
|
+
tslib_1.__decorate([
|
|
38
|
+
(0, typeorm_1.Column)({ nullable: true, ...(0, shell_1.longTextColumn)() }),
|
|
39
|
+
(0, type_graphql_1.Field)({ nullable: true, description: 'The recipe JSON (figure-model V3Recipe).' }),
|
|
40
|
+
tslib_1.__metadata("design:type", String)
|
|
41
|
+
], FigureRecipe.prototype, "source", void 0);
|
|
42
|
+
tslib_1.__decorate([
|
|
43
|
+
(0, typeorm_1.Column)({ nullable: true, default: 'released' }),
|
|
44
|
+
(0, type_graphql_1.Field)({ nullable: true, description: "'draft' or 'released'. Only released recipes are offered in the modeller." }),
|
|
45
|
+
tslib_1.__metadata("design:type", String)
|
|
46
|
+
], FigureRecipe.prototype, "state", void 0);
|
|
47
|
+
tslib_1.__decorate([
|
|
48
|
+
(0, typeorm_1.CreateDateColumn)(),
|
|
49
|
+
(0, type_graphql_1.Field)({ nullable: true, description: 'When the recipe was created.' }),
|
|
50
|
+
tslib_1.__metadata("design:type", Date)
|
|
51
|
+
], FigureRecipe.prototype, "createdAt", void 0);
|
|
52
|
+
tslib_1.__decorate([
|
|
53
|
+
(0, typeorm_1.UpdateDateColumn)(),
|
|
54
|
+
(0, type_graphql_1.Field)({ nullable: true, description: 'When the recipe was last changed.' }),
|
|
55
|
+
tslib_1.__metadata("design:type", Date)
|
|
56
|
+
], FigureRecipe.prototype, "updatedAt", void 0);
|
|
57
|
+
tslib_1.__decorate([
|
|
58
|
+
(0, typeorm_1.DeleteDateColumn)(),
|
|
59
|
+
(0, type_graphql_1.Field)({ nullable: true, description: 'When the recipe was deleted.' }),
|
|
60
|
+
tslib_1.__metadata("design:type", Date)
|
|
61
|
+
], FigureRecipe.prototype, "deletedAt", void 0);
|
|
62
|
+
exports.FigureRecipe = FigureRecipe = tslib_1.__decorate([
|
|
63
|
+
(0, typeorm_1.Entity)(),
|
|
64
|
+
(0, typeorm_1.Index)('ix_figure_recipe_1', (recipe) => [recipe.domain, recipe.name], { unique: true, where: '"deleted_at" IS NULL' }),
|
|
65
|
+
(0, type_graphql_1.ObjectType)({ description: 'A recipe: a list of figure authoring commands with parameters (ADR-0095).' })
|
|
66
|
+
], FigureRecipe);
|
|
67
|
+
//# sourceMappingURL=figure-recipe.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"figure-recipe.js","sourceRoot":"","sources":["../../../server/service/figure-recipe/figure-recipe.ts"],"names":[],"mappings":";;;;AAAA,qCAAoJ;AACpJ,+CAAoD;AAEpD,iDAA8D;AAE9D;;;;;;GAMG;AAII,IAAM,YAAY,GAAlB,MAAM,YAAY;CAmCxB,CAAA;AAnCY,oCAAY;AAGd;IAFR,IAAA,gCAAsB,EAAC,MAAM,CAAC;IAC9B,IAAA,oBAAK,EAAC,IAAI,CAAC,EAAE,CAAC,iBAAE,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,mCAAmC,EAAE,CAAC;;wCACpE;AAIpB;IAFC,IAAA,mBAAS,EAAC,IAAI,CAAC,EAAE,CAAC,cAAM,CAAC;IACzB,IAAA,oBAAK,EAAC,IAAI,CAAC,EAAE,CAAC,cAAM,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,oCAAoC,EAAE,CAAC;sCACpF,cAAM;4CAAA;AAGf;IADC,IAAA,oBAAU,EAAC,CAAC,MAAoB,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC;;8CACnC;AAIjB;IAFC,IAAA,gBAAM,GAAE;IACR,IAAA,oBAAK,EAAC,EAAE,WAAW,EAAE,qEAAqE,EAAE,CAAC;;0CACjF;AAIb;IAFC,IAAA,gBAAM,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,GAAG,IAAA,sBAAc,GAAE,EAAE,CAAC;IAC/C,IAAA,oBAAK,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,0CAA0C,EAAE,CAAC;;4CACpE;AAIf;IAFC,IAAA,gBAAM,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,OAAO,EAAE,UAAU,EAAE,CAAC;IAC/C,IAAA,oBAAK,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,2EAA2E,EAAE,CAAC;;2CACxF;AAI5B;IAFC,IAAA,0BAAgB,GAAE;IAClB,IAAA,oBAAK,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,8BAA8B,EAAE,CAAC;sCAC3D,IAAI;+CAAA;AAIhB;IAFC,IAAA,0BAAgB,GAAE;IAClB,IAAA,oBAAK,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,mCAAmC,EAAE,CAAC;sCAChE,IAAI;+CAAA;AAIhB;IAFC,IAAA,0BAAgB,GAAE;IAClB,IAAA,oBAAK,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,8BAA8B,EAAE,CAAC;sCAC3D,IAAI;+CAAA;uBAlCL,YAAY;IAHxB,IAAA,gBAAM,GAAE;IACR,IAAA,eAAK,EAAC,oBAAoB,EAAE,CAAC,MAAoB,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,sBAAsB,EAAE,CAAC;IACpI,IAAA,yBAAU,EAAC,EAAE,WAAW,EAAE,2EAA2E,EAAE,CAAC;GAC5F,YAAY,CAmCxB","sourcesContent":["import { Column, CreateDateColumn, DeleteDateColumn, Entity, Index, ManyToOne, PrimaryGeneratedColumn, RelationId, UpdateDateColumn } from 'typeorm'\nimport { Field, ID, ObjectType } from 'type-graphql'\n\nimport { Domain, longTextColumn } from '@things-factory/shell'\n\n/**\n * FigureRecipe — 조각 하나(ADR-0095).\n *\n * 조각은 매개변수가 붙은 제안 명령 목록이다. 형식은 `@hatiolab/figure-model` 의 `V3Recipe` 가 정하고, 여기에는\n * 그 원본을 통째로 담는다 — Figure 가 자산을 `source` 로 담는 것과 같다. 매개변수 · 명령을 컬럼으로 두지 않는다.\n * 넣은 뒤의 부품은 조각과 이어지지 않으므로, 이 행을 고치거나 지워도 도형은 바뀌지 않는다.\n */\n@Entity()\n@Index('ix_figure_recipe_1', (recipe: FigureRecipe) => [recipe.domain, recipe.name], { unique: true, where: '\"deleted_at\" IS NULL' })\n@ObjectType({ description: 'A recipe: a list of figure authoring commands with parameters (ADR-0095).' })\nexport class FigureRecipe {\n @PrimaryGeneratedColumn('uuid')\n @Field(type => ID, { nullable: true, description: 'Unique identifier for the recipe.' })\n readonly id?: string\n\n @ManyToOne(type => Domain)\n @Field(type => Domain, { nullable: true, description: 'The domain this recipe belongs to.' })\n domain?: Domain\n\n @RelationId((recipe: FigureRecipe) => recipe.domain)\n domainId?: string\n\n @Column()\n @Field({ description: 'The recipe name, unique per domain: lower case, digits and hyphens.' })\n name?: string\n\n @Column({ nullable: true, ...longTextColumn() })\n @Field({ nullable: true, description: 'The recipe JSON (figure-model V3Recipe).' })\n source?: string\n\n @Column({ nullable: true, default: 'released' })\n @Field({ nullable: true, description: \"'draft' or 'released'. Only released recipes are offered in the modeller.\" })\n state?: 'draft' | 'released'\n\n @CreateDateColumn()\n @Field({ nullable: true, description: 'When the recipe was created.' })\n createdAt?: Date\n\n @UpdateDateColumn()\n @Field({ nullable: true, description: 'When the recipe was last changed.' })\n updatedAt?: Date\n\n @DeleteDateColumn()\n @Field({ nullable: true, description: 'When the recipe was deleted.' })\n deletedAt?: Date\n}\n"]}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.resolvers = exports.entities = void 0;
|
|
4
|
+
const figure_recipe_js_1 = require("./figure-recipe.js");
|
|
5
|
+
const figure_recipe_resolver_js_1 = require("./figure-recipe-resolver.js");
|
|
6
|
+
exports.entities = [figure_recipe_js_1.FigureRecipe];
|
|
7
|
+
exports.resolvers = [figure_recipe_resolver_js_1.FigureRecipeResolver];
|
|
8
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../server/service/figure-recipe/index.ts"],"names":[],"mappings":";;;AAAA,yDAAiD;AACjD,2EAAkE;AAErD,QAAA,QAAQ,GAAG,CAAC,+BAAY,CAAC,CAAA;AACzB,QAAA,SAAS,GAAG,CAAC,gDAAoB,CAAC,CAAA","sourcesContent":["import { FigureRecipe } from './figure-recipe.js'\nimport { FigureRecipeResolver } from './figure-recipe-resolver.js'\n\nexport const entities = [FigureRecipe]\nexport const resolvers = [FigureRecipeResolver]\n"]}
|
|
@@ -2,8 +2,10 @@ export * from './figure/figure.js';
|
|
|
2
2
|
export * from './figure/figure-type.js';
|
|
3
3
|
export * from './figure/figure-format.js';
|
|
4
4
|
export * from './figure/figure-history.js';
|
|
5
|
-
export
|
|
5
|
+
export * from './figure-recipe/figure-recipe.js';
|
|
6
|
+
export { recipesFor, saveRecipe, seedBuiltInRecipes, builtInRecipes } from './figure-recipe/figure-recipe-store.js';
|
|
7
|
+
export declare const entities: typeof import("./figure-recipe/figure-recipe.js").FigureRecipe[];
|
|
6
8
|
export declare const subscribers: typeof import("./figure/event-subscriber.js").FigureHistoryEntitySubscriber[];
|
|
7
9
|
export declare const schema: {
|
|
8
|
-
resolverClasses: (typeof import("./figure/figure-query.js").FigureQuery | typeof import("./figure/figure-mutation.js").FigureMutation)[];
|
|
10
|
+
resolverClasses: (typeof import("./figure/figure-query.js").FigureQuery | typeof import("./figure/figure-mutation.js").FigureMutation | typeof import("./figure-recipe/figure-recipe-resolver.js").FigureRecipeResolver)[];
|
|
9
11
|
};
|
|
@@ -1,15 +1,22 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.schema = exports.subscribers = exports.entities = void 0;
|
|
3
|
+
exports.schema = exports.subscribers = exports.entities = exports.builtInRecipes = exports.seedBuiltInRecipes = exports.saveRecipe = exports.recipesFor = void 0;
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
5
|
// Entity types
|
|
6
6
|
tslib_1.__exportStar(require("./figure/figure.js"), exports);
|
|
7
7
|
tslib_1.__exportStar(require("./figure/figure-type.js"), exports);
|
|
8
8
|
tslib_1.__exportStar(require("./figure/figure-format.js"), exports);
|
|
9
9
|
tslib_1.__exportStar(require("./figure/figure-history.js"), exports);
|
|
10
|
+
tslib_1.__exportStar(require("./figure-recipe/figure-recipe.js"), exports);
|
|
11
|
+
var figure_recipe_store_js_1 = require("./figure-recipe/figure-recipe-store.js");
|
|
12
|
+
Object.defineProperty(exports, "recipesFor", { enumerable: true, get: function () { return figure_recipe_store_js_1.recipesFor; } });
|
|
13
|
+
Object.defineProperty(exports, "saveRecipe", { enumerable: true, get: function () { return figure_recipe_store_js_1.saveRecipe; } });
|
|
14
|
+
Object.defineProperty(exports, "seedBuiltInRecipes", { enumerable: true, get: function () { return figure_recipe_store_js_1.seedBuiltInRecipes; } });
|
|
15
|
+
Object.defineProperty(exports, "builtInRecipes", { enumerable: true, get: function () { return figure_recipe_store_js_1.builtInRecipes; } });
|
|
10
16
|
// Entities, resolvers
|
|
11
17
|
const index_js_1 = require("./figure/index.js");
|
|
12
|
-
|
|
18
|
+
const index_js_2 = require("./figure-recipe/index.js");
|
|
19
|
+
exports.entities = [...index_js_1.entities, ...index_js_2.entities];
|
|
13
20
|
/* 판본 스냅샷을 뜨는 구독자. 셸이 이 이름으로 모아 TypeORM 에 등록한다(board-service 와 같다). */
|
|
14
21
|
exports.subscribers = [...index_js_1.subscribers];
|
|
15
22
|
/*
|
|
@@ -23,6 +30,6 @@ exports.subscribers = [...index_js_1.subscribers];
|
|
|
23
30
|
* board-service, ops-master and font-base all export the shape below.
|
|
24
31
|
*/
|
|
25
32
|
exports.schema = {
|
|
26
|
-
resolverClasses: [...index_js_1.resolvers]
|
|
33
|
+
resolverClasses: [...index_js_1.resolvers, ...index_js_2.resolvers]
|
|
27
34
|
};
|
|
28
35
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../server/service/index.ts"],"names":[],"mappings":";;;;AAAA,eAAe;AACf,6DAAkC;AAClC,kEAAuC;AACvC,oEAAyC;AACzC,qEAA0C;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../server/service/index.ts"],"names":[],"mappings":";;;;AAAA,eAAe;AACf,6DAAkC;AAClC,kEAAuC;AACvC,oEAAyC;AACzC,qEAA0C;AAC1C,2EAAgD;AAChD,iFAAmH;AAA1G,oHAAA,UAAU,OAAA;AAAE,oHAAA,UAAU,OAAA;AAAE,4HAAA,kBAAkB,OAAA;AAAE,wHAAA,cAAc,OAAA;AAEnE,sBAAsB;AACtB,gDAI0B;AAC1B,uDAAmG;AAEtF,QAAA,QAAQ,GAAG,CAAC,GAAG,mBAAc,EAAE,GAAG,mBAAc,CAAC,CAAA;AAE9D,sEAAsE;AACzD,QAAA,WAAW,GAAG,CAAC,GAAG,sBAAiB,CAAC,CAAA;AAEjD;;;;;;;;;GASG;AACU,QAAA,MAAM,GAAG;IACpB,eAAe,EAAE,CAAC,GAAG,oBAAe,EAAE,GAAG,oBAAe,CAAC;CAC1D,CAAA","sourcesContent":["// Entity types\nexport * from './figure/figure.js'\nexport * from './figure/figure-type.js'\nexport * from './figure/figure-format.js'\nexport * from './figure/figure-history.js'\nexport * from './figure-recipe/figure-recipe.js'\nexport { recipesFor, saveRecipe, seedBuiltInRecipes, builtInRecipes } from './figure-recipe/figure-recipe-store.js'\n\n// Entities, resolvers\nimport {\n entities as FigureEntities,\n resolvers as FigureResolvers,\n subscribers as FigureSubscribers\n} from './figure/index.js'\nimport { entities as RecipeEntities, resolvers as RecipeResolvers } from './figure-recipe/index.js'\n\nexport const entities = [...FigureEntities, ...RecipeEntities]\n\n/* 판본 스냅샷을 뜨는 구독자. 셸이 이 이름으로 모아 TypeORM 에 등록한다(board-service 와 같다). */\nexport const subscribers = [...FigureSubscribers]\n\n/*\n * The shell reads `schema.resolverClasses` from every module — nothing else.\n *\n * shell/dist-server/schema.js orderedModuleNames.map(dep => loader(dep).schema)\n *\n * This module used to export the classes as a bare `resolvers` array, a name the shell never looks\n * at. The table was migrated and the resolver classes were compiled, and still every query failed\n * with `Cannot query field \"figures\" on type \"Query\"` — the field was not in the schema at all.\n * board-service, ops-master and font-base all export the shape below.\n */\nexport const schema = {\n resolverClasses: [...FigureResolvers, ...RecipeResolvers]\n}\n"]}
|