@things-factory/figure-service 10.1.69 → 10.1.71
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 +6 -11
- package/dist-server/index.js.map +1 -1
- package/dist-server/routers/figure-thumbnail-router.js +22 -0
- package/dist-server/routers/figure-thumbnail-router.js.map +1 -1
- package/dist-server/service/figure-recipe/figure-recipe-resolver.d.ts +4 -4
- package/dist-server/service/figure-recipe/figure-recipe-resolver.js +36 -26
- package/dist-server/service/figure-recipe/figure-recipe-resolver.js.map +1 -1
- package/dist-server/service/figure-recipe/figure-recipe-templates.d.ts +28 -0
- package/dist-server/service/figure-recipe/figure-recipe-templates.js +57 -0
- package/dist-server/service/figure-recipe/figure-recipe-templates.js.map +1 -0
- package/dist-server/service/figure-recipe/figure-recipe-type.d.ts +11 -0
- package/dist-server/service/figure-recipe/figure-recipe-type.js +48 -0
- package/dist-server/service/figure-recipe/figure-recipe-type.js.map +1 -0
- package/dist-server/service/figure-recipe/index.d.ts +2 -4
- package/dist-server/service/figure-recipe/index.js +2 -4
- package/dist-server/service/figure-recipe/index.js.map +1 -1
- package/dist-server/service/index.d.ts +4 -4
- package/dist-server/service/index.js +7 -8
- package/dist-server/service/index.js.map +1 -1
- package/dist-server/tsconfig.tsbuildinfo +1 -1
- package/package.json +6 -4
- package/recipes/_lib/model.mts +71 -0
- package/recipes/air-cylinder/build.mts +14 -0
- package/recipes/air-cylinder/facts.md +3 -0
- package/recipes/air-cylinder/guide.en.md +18 -0
- package/recipes/air-cylinder/guide.ko.md +18 -0
- package/recipes/air-cylinder/models/default.json +1 -0
- package/recipes/air-cylinder/recipe.json +129 -0
- package/recipes/air-cylinder/spec.json +45 -0
- package/recipes/air-cylinder/thumbnail.png +0 -0
- package/recipes/air-shower/build.mts +14 -0
- package/recipes/air-shower/facts.md +3 -0
- package/recipes/air-shower/guide.en.md +17 -0
- package/recipes/air-shower/guide.ko.md +17 -0
- package/recipes/air-shower/models/default.json +1 -0
- package/recipes/air-shower/recipe.json +111 -0
- package/recipes/air-shower/spec.json +18 -0
- package/recipes/air-shower/thumbnail.png +0 -0
- package/recipes/barrier-gate/build.mts +11 -0
- package/recipes/barrier-gate/facts.md +3 -0
- package/recipes/barrier-gate/guide.en.md +18 -0
- package/recipes/barrier-gate/guide.ko.md +18 -0
- package/recipes/barrier-gate/models/default.json +1 -0
- package/recipes/barrier-gate/recipe.json +87 -0
- package/recipes/barrier-gate/spec.json +45 -0
- package/recipes/barrier-gate/thumbnail.png +0 -0
- package/recipes/base-frame/build.mts +11 -0
- package/recipes/base-frame/facts.md +3 -0
- package/recipes/base-frame/guide.en.md +18 -0
- package/recipes/base-frame/guide.ko.md +18 -0
- package/recipes/base-frame/models/default.json +1 -0
- package/recipes/base-frame/recipe.json +259 -0
- package/recipes/base-frame/spec.json +72 -0
- package/recipes/base-frame/thumbnail.png +0 -0
- package/recipes/belt-surface/build.mts +12 -0
- package/recipes/belt-surface/facts.md +3 -0
- package/recipes/belt-surface/guide.en.md +18 -0
- package/recipes/belt-surface/guide.ko.md +18 -0
- package/recipes/belt-surface/models/default.json +1 -0
- package/recipes/belt-surface/recipe.json +116 -0
- package/recipes/belt-surface/spec.json +69 -0
- package/recipes/belt-surface/thumbnail.png +0 -0
- package/recipes/bin-row/build.mts +11 -0
- package/recipes/bin-row/facts.md +3 -0
- package/recipes/bin-row/guide.en.md +18 -0
- package/recipes/bin-row/guide.ko.md +18 -0
- package/recipes/bin-row/models/default.json +1 -0
- package/recipes/bin-row/recipe.json +87 -0
- package/recipes/bin-row/spec.json +45 -0
- package/recipes/bin-row/thumbnail.png +0 -0
- package/recipes/bollard-row/build.mts +11 -0
- package/recipes/bollard-row/facts.md +3 -0
- package/recipes/bollard-row/guide.en.md +18 -0
- package/recipes/bollard-row/guide.ko.md +18 -0
- package/recipes/bollard-row/models/default.json +1 -0
- package/recipes/bollard-row/recipe.json +107 -0
- package/recipes/bollard-row/spec.json +71 -0
- package/recipes/bollard-row/thumbnail.png +0 -0
- package/recipes/buzzer/build.mts +10 -0
- package/recipes/buzzer/facts.md +3 -0
- package/recipes/buzzer/guide.en.md +17 -0
- package/recipes/buzzer/guide.ko.md +17 -0
- package/recipes/buzzer/models/default.json +1 -0
- package/recipes/buzzer/recipe.json +68 -0
- package/recipes/buzzer/spec.json +18 -0
- package/recipes/buzzer/thumbnail.png +0 -0
- package/recipes/cabinet-doors/build.mts +21 -0
- package/recipes/cabinet-doors/facts.md +3 -0
- package/recipes/cabinet-doors/guide.en.md +19 -0
- package/recipes/cabinet-doors/guide.ko.md +19 -0
- package/recipes/cabinet-doors/models/default.json +1 -0
- package/recipes/cabinet-doors/models/doors=1.json +1 -0
- package/recipes/cabinet-doors/models/doors=2.json +1 -0
- package/recipes/cabinet-doors/recipe.json +240 -0
- package/recipes/cabinet-doors/spec.json +36 -0
- package/recipes/cabinet-doors/thumbnail.png +0 -0
- package/recipes/cable-tray/build.mts +16 -0
- package/recipes/cable-tray/facts.md +3 -0
- package/recipes/cable-tray/guide.en.md +18 -0
- package/recipes/cable-tray/guide.ko.md +18 -0
- package/recipes/cable-tray/models/default.json +1 -0
- package/recipes/cable-tray/recipe.json +198 -0
- package/recipes/cable-tray/spec.json +45 -0
- package/recipes/cable-tray/thumbnail.png +0 -0
- package/recipes/camera-mount/build.mts +10 -0
- package/recipes/camera-mount/facts.md +3 -0
- package/recipes/camera-mount/guide.en.md +16 -0
- package/recipes/camera-mount/guide.ko.md +16 -0
- package/recipes/camera-mount/models/default.json +1 -0
- package/recipes/camera-mount/recipe.json +108 -0
- package/recipes/camera-mount/spec.json +18 -0
- package/recipes/camera-mount/thumbnail.png +0 -0
- package/recipes/canopy/build.mts +17 -0
- package/recipes/canopy/facts.md +3 -0
- package/recipes/canopy/guide.en.md +18 -0
- package/recipes/canopy/guide.ko.md +18 -0
- package/recipes/canopy/models/default.json +1 -0
- package/recipes/canopy/recipe.json +281 -0
- package/recipes/canopy/spec.json +81 -0
- package/recipes/canopy/thumbnail.png +0 -0
- package/recipes/cart/build.mts +24 -0
- package/recipes/cart/facts.md +3 -0
- package/recipes/cart/guide.en.md +16 -0
- package/recipes/cart/guide.ko.md +16 -0
- package/recipes/cart/models/default.json +1 -0
- package/recipes/cart/recipe.json +555 -0
- package/recipes/cart/spec.json +11 -0
- package/recipes/cart/thumbnail.png +0 -0
- package/recipes/cart-handle/build.mts +13 -0
- package/recipes/cart-handle/facts.md +3 -0
- package/recipes/cart-handle/guide.en.md +16 -0
- package/recipes/cart-handle/guide.ko.md +16 -0
- package/recipes/cart-handle/models/default.json +1 -0
- package/recipes/cart-handle/recipe.json +161 -0
- package/recipes/cart-handle/spec.json +18 -0
- package/recipes/cart-handle/thumbnail.png +0 -0
- package/recipes/casters-four/build.mts +16 -0
- package/recipes/casters-four/facts.md +3 -0
- package/recipes/casters-four/guide.en.md +19 -0
- package/recipes/casters-four/guide.ko.md +19 -0
- package/recipes/casters-four/models/default.json +1 -0
- package/recipes/casters-four/recipe.json +409 -0
- package/recipes/casters-four/spec.json +72 -0
- package/recipes/casters-four/thumbnail.png +0 -0
- package/recipes/ceiling-rail-carriage/build.mts +15 -0
- package/recipes/ceiling-rail-carriage/facts.md +3 -0
- package/recipes/ceiling-rail-carriage/guide.en.md +17 -0
- package/recipes/ceiling-rail-carriage/guide.ko.md +17 -0
- package/recipes/ceiling-rail-carriage/models/default.json +1 -0
- package/recipes/ceiling-rail-carriage/recipe.json +127 -0
- package/recipes/ceiling-rail-carriage/spec.json +19 -0
- package/recipes/ceiling-rail-carriage/thumbnail.png +0 -0
- package/recipes/chain-rails/build.mts +15 -0
- package/recipes/chain-rails/facts.md +3 -0
- package/recipes/chain-rails/guide.en.md +18 -0
- package/recipes/chain-rails/guide.ko.md +18 -0
- package/recipes/chain-rails/models/default.json +1 -0
- package/recipes/chain-rails/recipe.json +166 -0
- package/recipes/chain-rails/spec.json +54 -0
- package/recipes/chain-rails/thumbnail.png +0 -0
- package/recipes/charging-station/build.mts +9 -0
- package/recipes/charging-station/facts.md +3 -0
- package/recipes/charging-station/guide.en.md +16 -0
- package/recipes/charging-station/guide.ko.md +16 -0
- package/recipes/charging-station/models/default.json +1 -0
- package/recipes/charging-station/recipe.json +105 -0
- package/recipes/charging-station/spec.json +18 -0
- package/recipes/charging-station/thumbnail.png +0 -0
- package/recipes/column-row/build.mts +11 -0
- package/recipes/column-row/facts.md +3 -0
- package/recipes/column-row/guide.en.md +18 -0
- package/recipes/column-row/guide.ko.md +18 -0
- package/recipes/column-row/models/default.json +1 -0
- package/recipes/column-row/recipe.json +103 -0
- package/recipes/column-row/spec.json +71 -0
- package/recipes/column-row/thumbnail.png +0 -0
- package/recipes/control-cabinet/build.mts +14 -0
- package/recipes/control-cabinet/facts.md +3 -0
- package/recipes/control-cabinet/guide.en.md +17 -0
- package/recipes/control-cabinet/guide.ko.md +17 -0
- package/recipes/control-cabinet/models/default.json +1 -0
- package/recipes/control-cabinet/recipe.json +111 -0
- package/recipes/control-cabinet/spec.json +18 -0
- package/recipes/control-cabinet/thumbnail.png +0 -0
- package/recipes/conveyor-skirts/build.mts +9 -0
- package/recipes/conveyor-skirts/facts.md +3 -0
- package/recipes/conveyor-skirts/guide.en.md +16 -0
- package/recipes/conveyor-skirts/guide.ko.md +16 -0
- package/recipes/conveyor-skirts/models/default.json +1 -0
- package/recipes/conveyor-skirts/recipe.json +141 -0
- package/recipes/conveyor-skirts/spec.json +18 -0
- package/recipes/conveyor-skirts/thumbnail.png +0 -0
- package/recipes/counter-display/build.mts +13 -0
- package/recipes/counter-display/facts.md +3 -0
- package/recipes/counter-display/guide.en.md +17 -0
- package/recipes/counter-display/guide.ko.md +17 -0
- package/recipes/counter-display/models/default.json +1 -0
- package/recipes/counter-display/recipe.json +106 -0
- package/recipes/counter-display/spec.json +18 -0
- package/recipes/counter-display/thumbnail.png +0 -0
- package/recipes/dock-bumpers/build.mts +9 -0
- package/recipes/dock-bumpers/facts.md +3 -0
- package/recipes/dock-bumpers/guide.en.md +16 -0
- package/recipes/dock-bumpers/guide.ko.md +16 -0
- package/recipes/dock-bumpers/models/default.json +1 -0
- package/recipes/dock-bumpers/recipe.json +107 -0
- package/recipes/dock-bumpers/spec.json +18 -0
- package/recipes/dock-bumpers/thumbnail.png +0 -0
- package/recipes/dock-leveler/build.mts +11 -0
- package/recipes/dock-leveler/facts.md +3 -0
- package/recipes/dock-leveler/guide.en.md +16 -0
- package/recipes/dock-leveler/guide.ko.md +16 -0
- package/recipes/dock-leveler/models/default.json +1 -0
- package/recipes/dock-leveler/recipe.json +69 -0
- package/recipes/dock-leveler/spec.json +18 -0
- package/recipes/dock-leveler/thumbnail.png +0 -0
- package/recipes/double-hinged-door/build.mts +19 -0
- package/recipes/double-hinged-door/facts.md +3 -0
- package/recipes/double-hinged-door/guide.en.md +19 -0
- package/recipes/double-hinged-door/guide.ko.md +19 -0
- package/recipes/double-hinged-door/models/default.json +1 -0
- package/recipes/double-hinged-door/recipe.json +273 -0
- package/recipes/double-hinged-door/spec.json +69 -0
- package/recipes/double-hinged-door/thumbnail.png +0 -0
- package/recipes/drawer-stack/build.mts +17 -0
- package/recipes/drawer-stack/facts.md +3 -0
- package/recipes/drawer-stack/guide.en.md +18 -0
- package/recipes/drawer-stack/guide.ko.md +18 -0
- package/recipes/drawer-stack/models/default.json +1 -0
- package/recipes/drawer-stack/models/drawers=2.json +1 -0
- package/recipes/drawer-stack/models/drawers=3.json +1 -0
- package/recipes/drawer-stack/models/drawers=4.json +1 -0
- package/recipes/drawer-stack/recipe.json +789 -0
- package/recipes/drawer-stack/spec.json +37 -0
- package/recipes/drawer-stack/thumbnail.png +0 -0
- package/recipes/drip-tray/build.mts +12 -0
- package/recipes/drip-tray/facts.md +3 -0
- package/recipes/drip-tray/guide.en.md +16 -0
- package/recipes/drip-tray/guide.ko.md +16 -0
- package/recipes/drip-tray/models/default.json +1 -0
- package/recipes/drip-tray/recipe.json +86 -0
- package/recipes/drip-tray/spec.json +18 -0
- package/recipes/drip-tray/thumbnail.png +0 -0
- package/recipes/duct-fan/build.mts +14 -0
- package/recipes/duct-fan/facts.md +3 -0
- package/recipes/duct-fan/guide.en.md +16 -0
- package/recipes/duct-fan/guide.ko.md +16 -0
- package/recipes/duct-fan/models/default.json +1 -0
- package/recipes/duct-fan/recipe.json +122 -0
- package/recipes/duct-fan/spec.json +18 -0
- package/recipes/duct-fan/thumbnail.png +0 -0
- package/recipes/emergency-stop/build.mts +14 -0
- package/recipes/emergency-stop/facts.md +3 -0
- package/recipes/emergency-stop/guide.en.md +17 -0
- package/recipes/emergency-stop/guide.ko.md +17 -0
- package/recipes/emergency-stop/models/default.json +1 -0
- package/recipes/emergency-stop/recipe.json +109 -0
- package/recipes/emergency-stop/spec.json +18 -0
- package/recipes/emergency-stop/thumbnail.png +0 -0
- package/recipes/end-covers/build.mts +13 -0
- package/recipes/end-covers/facts.md +3 -0
- package/recipes/end-covers/guide.en.md +17 -0
- package/recipes/end-covers/guide.ko.md +17 -0
- package/recipes/end-covers/models/default.json +1 -0
- package/recipes/end-covers/recipe.json +141 -0
- package/recipes/end-covers/spec.json +18 -0
- package/recipes/end-covers/thumbnail.png +0 -0
- package/recipes/ffu-row/build.mts +11 -0
- package/recipes/ffu-row/facts.md +3 -0
- package/recipes/ffu-row/guide.en.md +18 -0
- package/recipes/ffu-row/guide.ko.md +18 -0
- package/recipes/ffu-row/models/default.json +1 -0
- package/recipes/ffu-row/recipe.json +82 -0
- package/recipes/ffu-row/spec.json +45 -0
- package/recipes/ffu-row/thumbnail.png +0 -0
- package/recipes/fire-extinguisher/build.mts +13 -0
- package/recipes/fire-extinguisher/facts.md +3 -0
- package/recipes/fire-extinguisher/guide.en.md +16 -0
- package/recipes/fire-extinguisher/guide.ko.md +16 -0
- package/recipes/fire-extinguisher/models/default.json +1 -0
- package/recipes/fire-extinguisher/recipe.json +114 -0
- package/recipes/fire-extinguisher/spec.json +18 -0
- package/recipes/fire-extinguisher/thumbnail.png +0 -0
- package/recipes/first-aid-box/build.mts +9 -0
- package/recipes/first-aid-box/facts.md +3 -0
- package/recipes/first-aid-box/guide.en.md +16 -0
- package/recipes/first-aid-box/guide.ko.md +16 -0
- package/recipes/first-aid-box/models/default.json +1 -0
- package/recipes/first-aid-box/recipe.json +97 -0
- package/recipes/first-aid-box/spec.json +18 -0
- package/recipes/first-aid-box/thumbnail.png +0 -0
- package/recipes/floor-zone/build.mts +17 -0
- package/recipes/floor-zone/facts.md +3 -0
- package/recipes/floor-zone/guide.en.md +18 -0
- package/recipes/floor-zone/guide.ko.md +18 -0
- package/recipes/floor-zone/models/default.json +1 -0
- package/recipes/floor-zone/recipe.json +257 -0
- package/recipes/floor-zone/spec.json +72 -0
- package/recipes/floor-zone/thumbnail.png +0 -0
- package/recipes/folding-door/build.mts +20 -0
- package/recipes/folding-door/facts.md +3 -0
- package/recipes/folding-door/guide.en.md +18 -0
- package/recipes/folding-door/guide.ko.md +18 -0
- package/recipes/folding-door/models/default.json +1 -0
- package/recipes/folding-door/recipe.json +217 -0
- package/recipes/folding-door/spec.json +44 -0
- package/recipes/folding-door/thumbnail.png +0 -0
- package/recipes/fork/build.mts +13 -0
- package/recipes/fork/facts.md +3 -0
- package/recipes/fork/guide.en.md +18 -0
- package/recipes/fork/guide.ko.md +18 -0
- package/recipes/fork/models/default.json +1 -0
- package/recipes/fork/recipe.json +136 -0
- package/recipes/fork/spec.json +45 -0
- package/recipes/fork/thumbnail.png +0 -0
- package/recipes/gantry-frame/build.mts +13 -0
- package/recipes/gantry-frame/facts.md +3 -0
- package/recipes/gantry-frame/guide.en.md +18 -0
- package/recipes/gantry-frame/guide.ko.md +18 -0
- package/recipes/gantry-frame/models/default.json +1 -0
- package/recipes/gantry-frame/recipe.json +178 -0
- package/recipes/gantry-frame/spec.json +63 -0
- package/recipes/gantry-frame/thumbnail.png +0 -0
- package/recipes/gripper-2f/build.mts +16 -0
- package/recipes/gripper-2f/facts.md +3 -0
- package/recipes/gripper-2f/guide.en.md +18 -0
- package/recipes/gripper-2f/guide.ko.md +18 -0
- package/recipes/gripper-2f/models/default.json +1 -0
- package/recipes/gripper-2f/recipe.json +172 -0
- package/recipes/gripper-2f/spec.json +45 -0
- package/recipes/gripper-2f/thumbnail.png +0 -0
- package/recipes/guard-cover/build.mts +13 -0
- package/recipes/guard-cover/facts.md +3 -0
- package/recipes/guard-cover/guide.en.md +18 -0
- package/recipes/guard-cover/guide.ko.md +18 -0
- package/recipes/guard-cover/models/default.json +1 -0
- package/recipes/guard-cover/recipe.json +92 -0
- package/recipes/guard-cover/spec.json +18 -0
- package/recipes/guard-cover/thumbnail.png +0 -0
- package/recipes/handrail/build.mts +15 -0
- package/recipes/handrail/facts.md +3 -0
- package/recipes/handrail/guide.en.md +18 -0
- package/recipes/handrail/guide.ko.md +18 -0
- package/recipes/handrail/models/default.json +1 -0
- package/recipes/handrail/recipe.json +140 -0
- package/recipes/handrail/spec.json +45 -0
- package/recipes/handrail/thumbnail.png +0 -0
- package/recipes/hatch/build.mts +17 -0
- package/recipes/hatch/facts.md +3 -0
- package/recipes/hatch/guide.en.md +18 -0
- package/recipes/hatch/guide.ko.md +18 -0
- package/recipes/hatch/models/default.json +1 -0
- package/recipes/hatch/recipe.json +194 -0
- package/recipes/hatch/spec.json +69 -0
- package/recipes/hatch/thumbnail.png +0 -0
- package/recipes/hinged-door/build.mts +26 -0
- package/recipes/hinged-door/facts.md +21 -0
- package/recipes/hinged-door/guide.en.md +19 -0
- package/recipes/hinged-door/guide.ko.md +19 -0
- package/recipes/hinged-door/models/default.json +1 -0
- package/recipes/hinged-door/models/hinge=left.json +1 -0
- package/recipes/hinged-door/models/hinge=right.json +1 -0
- package/recipes/hinged-door/recipe.json +252 -0
- package/recipes/hinged-door/spec.json +23 -0
- package/recipes/hinged-door/thumbnail.png +0 -0
- package/recipes/hmi-monitor/build.mts +14 -0
- package/recipes/hmi-monitor/facts.md +3 -0
- package/recipes/hmi-monitor/guide.en.md +17 -0
- package/recipes/hmi-monitor/guide.ko.md +17 -0
- package/recipes/hmi-monitor/models/default.json +1 -0
- package/recipes/hmi-monitor/recipe.json +108 -0
- package/recipes/hmi-monitor/spec.json +18 -0
- package/recipes/hmi-monitor/thumbnail.png +0 -0
- package/recipes/hopper/build.mts +14 -0
- package/recipes/hopper/facts.md +3 -0
- package/recipes/hopper/guide.en.md +18 -0
- package/recipes/hopper/guide.ko.md +18 -0
- package/recipes/hopper/models/default.json +1 -0
- package/recipes/hopper/recipe.json +137 -0
- package/recipes/hopper/spec.json +22 -0
- package/recipes/hopper/thumbnail.png +0 -0
- package/recipes/interlock-switch/build.mts +8 -0
- package/recipes/interlock-switch/facts.md +3 -0
- package/recipes/interlock-switch/guide.en.md +17 -0
- package/recipes/interlock-switch/guide.ko.md +17 -0
- package/recipes/interlock-switch/models/default.json +1 -0
- package/recipes/interlock-switch/recipe.json +63 -0
- package/recipes/interlock-switch/spec.json +18 -0
- package/recipes/interlock-switch/thumbnail.png +0 -0
- package/recipes/junction-box/build.mts +8 -0
- package/recipes/junction-box/facts.md +3 -0
- package/recipes/junction-box/guide.en.md +16 -0
- package/recipes/junction-box/guide.ko.md +16 -0
- package/recipes/junction-box/models/default.json +1 -0
- package/recipes/junction-box/recipe.json +64 -0
- package/recipes/junction-box/spec.json +18 -0
- package/recipes/junction-box/thumbnail.png +0 -0
- package/recipes/ladder/build.mts +13 -0
- package/recipes/ladder/facts.md +3 -0
- package/recipes/ladder/guide.en.md +18 -0
- package/recipes/ladder/guide.ko.md +18 -0
- package/recipes/ladder/models/default.json +1 -0
- package/recipes/ladder/recipe.json +191 -0
- package/recipes/ladder/spec.json +44 -0
- package/recipes/ladder/thumbnail.png +0 -0
- package/recipes/legs-four/build.mts +12 -0
- package/recipes/legs-four/facts.md +3 -0
- package/recipes/legs-four/guide.en.md +18 -0
- package/recipes/legs-four/guide.ko.md +18 -0
- package/recipes/legs-four/models/default.json +1 -0
- package/recipes/legs-four/recipe.json +217 -0
- package/recipes/legs-four/spec.json +72 -0
- package/recipes/legs-four/thumbnail.png +0 -0
- package/recipes/leveling-feet/build.mts +11 -0
- package/recipes/leveling-feet/facts.md +3 -0
- package/recipes/leveling-feet/guide.en.md +18 -0
- package/recipes/leveling-feet/guide.ko.md +18 -0
- package/recipes/leveling-feet/models/default.json +1 -0
- package/recipes/leveling-feet/recipe.json +233 -0
- package/recipes/leveling-feet/spec.json +72 -0
- package/recipes/leveling-feet/thumbnail.png +0 -0
- package/recipes/lift-updown/build.mts +13 -0
- package/recipes/lift-updown/facts.md +3 -0
- package/recipes/lift-updown/guide.en.md +18 -0
- package/recipes/lift-updown/guide.ko.md +18 -0
- package/recipes/lift-updown/models/default.json +1 -0
- package/recipes/lift-updown/recipe.json +107 -0
- package/recipes/lift-updown/spec.json +45 -0
- package/recipes/lift-updown/thumbnail.png +0 -0
- package/recipes/light-curtain/build.mts +11 -0
- package/recipes/light-curtain/facts.md +3 -0
- package/recipes/light-curtain/guide.en.md +18 -0
- package/recipes/light-curtain/guide.ko.md +18 -0
- package/recipes/light-curtain/models/default.json +1 -0
- package/recipes/light-curtain/recipe.json +127 -0
- package/recipes/light-curtain/spec.json +54 -0
- package/recipes/light-curtain/thumbnail.png +0 -0
- package/recipes/limit-switch/build.mts +14 -0
- package/recipes/limit-switch/facts.md +3 -0
- package/recipes/limit-switch/guide.en.md +17 -0
- package/recipes/limit-switch/guide.ko.md +17 -0
- package/recipes/limit-switch/models/default.json +1 -0
- package/recipes/limit-switch/recipe.json +107 -0
- package/recipes/limit-switch/spec.json +17 -0
- package/recipes/limit-switch/thumbnail.png +0 -0
- package/recipes/linear-guide/build.mts +15 -0
- package/recipes/linear-guide/facts.md +3 -0
- package/recipes/linear-guide/guide.en.md +18 -0
- package/recipes/linear-guide/guide.ko.md +18 -0
- package/recipes/linear-guide/models/default.json +1 -0
- package/recipes/linear-guide/recipe.json +145 -0
- package/recipes/linear-guide/spec.json +44 -0
- package/recipes/linear-guide/thumbnail.png +0 -0
- package/recipes/locker-row/build.mts +11 -0
- package/recipes/locker-row/facts.md +3 -0
- package/recipes/locker-row/guide.en.md +18 -0
- package/recipes/locker-row/guide.ko.md +18 -0
- package/recipes/locker-row/models/default.json +1 -0
- package/recipes/locker-row/recipe.json +82 -0
- package/recipes/locker-row/spec.json +45 -0
- package/recipes/locker-row/thumbnail.png +0 -0
- package/recipes/motor-box/build.mts +10 -0
- package/recipes/motor-box/facts.md +3 -0
- package/recipes/motor-box/guide.en.md +17 -0
- package/recipes/motor-box/guide.ko.md +17 -0
- package/recipes/motor-box/models/default.json +1 -0
- package/recipes/motor-box/recipe.json +64 -0
- package/recipes/motor-box/spec.json +18 -0
- package/recipes/motor-box/thumbnail.png +0 -0
- package/recipes/observation-window/build.mts +16 -0
- package/recipes/observation-window/facts.md +3 -0
- package/recipes/observation-window/guide.en.md +19 -0
- package/recipes/observation-window/guide.ko.md +19 -0
- package/recipes/observation-window/models/default.json +1 -0
- package/recipes/observation-window/recipe.json +185 -0
- package/recipes/observation-window/spec.json +68 -0
- package/recipes/observation-window/thumbnail.png +0 -0
- package/recipes/operator-panel/build.mts +14 -0
- package/recipes/operator-panel/facts.md +3 -0
- package/recipes/operator-panel/guide.en.md +18 -0
- package/recipes/operator-panel/guide.ko.md +18 -0
- package/recipes/operator-panel/models/buttons=2.json +1 -0
- package/recipes/operator-panel/models/buttons=3.json +1 -0
- package/recipes/operator-panel/models/buttons=4.json +1 -0
- package/recipes/operator-panel/models/buttons=5.json +1 -0
- package/recipes/operator-panel/models/default.json +1 -0
- package/recipes/operator-panel/recipe.json +210 -0
- package/recipes/operator-panel/spec.json +38 -0
- package/recipes/operator-panel/thumbnail.png +0 -0
- package/recipes/pallet/build.mts +12 -0
- package/recipes/pallet/facts.md +3 -0
- package/recipes/pallet/guide.en.md +17 -0
- package/recipes/pallet/guide.ko.md +17 -0
- package/recipes/pallet/models/default.json +1 -0
- package/recipes/pallet/recipe.json +181 -0
- package/recipes/pallet/spec.json +18 -0
- package/recipes/pallet/thumbnail.png +0 -0
- package/recipes/partition-wall/build.mts +16 -0
- package/recipes/partition-wall/facts.md +3 -0
- package/recipes/partition-wall/guide.en.md +18 -0
- package/recipes/partition-wall/guide.ko.md +18 -0
- package/recipes/partition-wall/models/default.json +1 -0
- package/recipes/partition-wall/recipe.json +203 -0
- package/recipes/partition-wall/spec.json +54 -0
- package/recipes/partition-wall/thumbnail.png +0 -0
- package/recipes/pass-box/build.mts +14 -0
- package/recipes/pass-box/facts.md +3 -0
- package/recipes/pass-box/guide.en.md +17 -0
- package/recipes/pass-box/guide.ko.md +17 -0
- package/recipes/pass-box/models/default.json +1 -0
- package/recipes/pass-box/recipe.json +107 -0
- package/recipes/pass-box/spec.json +18 -0
- package/recipes/pass-box/thumbnail.png +0 -0
- package/recipes/peg-board/build.mts +14 -0
- package/recipes/peg-board/facts.md +3 -0
- package/recipes/peg-board/guide.en.md +17 -0
- package/recipes/peg-board/guide.ko.md +17 -0
- package/recipes/peg-board/models/default.json +1 -0
- package/recipes/peg-board/recipe.json +120 -0
- package/recipes/peg-board/spec.json +45 -0
- package/recipes/peg-board/thumbnail.png +0 -0
- package/recipes/photo-sensor-pair/build.mts +11 -0
- package/recipes/photo-sensor-pair/facts.md +3 -0
- package/recipes/photo-sensor-pair/guide.en.md +18 -0
- package/recipes/photo-sensor-pair/guide.ko.md +18 -0
- package/recipes/photo-sensor-pair/models/default.json +1 -0
- package/recipes/photo-sensor-pair/recipe.json +145 -0
- package/recipes/photo-sensor-pair/spec.json +54 -0
- package/recipes/photo-sensor-pair/thumbnail.png +0 -0
- package/recipes/pipe-run/build.mts +11 -0
- package/recipes/pipe-run/facts.md +3 -0
- package/recipes/pipe-run/guide.en.md +18 -0
- package/recipes/pipe-run/guide.ko.md +18 -0
- package/recipes/pipe-run/models/default.json +1 -0
- package/recipes/pipe-run/recipe.json +100 -0
- package/recipes/pipe-run/spec.json +44 -0
- package/recipes/pipe-run/thumbnail.png +0 -0
- package/recipes/platform/build.mts +14 -0
- package/recipes/platform/facts.md +3 -0
- package/recipes/platform/guide.en.md +18 -0
- package/recipes/platform/guide.ko.md +18 -0
- package/recipes/platform/models/default.json +1 -0
- package/recipes/platform/recipe.json +281 -0
- package/recipes/platform/spec.json +81 -0
- package/recipes/platform/thumbnail.png +0 -0
- package/recipes/power-box/build.mts +10 -0
- package/recipes/power-box/facts.md +3 -0
- package/recipes/power-box/guide.en.md +17 -0
- package/recipes/power-box/guide.ko.md +17 -0
- package/recipes/power-box/models/default.json +1 -0
- package/recipes/power-box/recipe.json +64 -0
- package/recipes/power-box/spec.json +18 -0
- package/recipes/power-box/thumbnail.png +0 -0
- package/recipes/pressure-gauge/build.mts +10 -0
- package/recipes/pressure-gauge/facts.md +3 -0
- package/recipes/pressure-gauge/guide.en.md +17 -0
- package/recipes/pressure-gauge/guide.ko.md +17 -0
- package/recipes/pressure-gauge/models/default.json +1 -0
- package/recipes/pressure-gauge/recipe.json +65 -0
- package/recipes/pressure-gauge/spec.json +18 -0
- package/recipes/pressure-gauge/thumbnail.png +0 -0
- package/recipes/pull-cord/build.mts +11 -0
- package/recipes/pull-cord/facts.md +3 -0
- package/recipes/pull-cord/guide.en.md +17 -0
- package/recipes/pull-cord/guide.ko.md +17 -0
- package/recipes/pull-cord/models/default.json +1 -0
- package/recipes/pull-cord/recipe.json +75 -0
- package/recipes/pull-cord/spec.json +18 -0
- package/recipes/pull-cord/thumbnail.png +0 -0
- package/recipes/pump/build.mts +13 -0
- package/recipes/pump/facts.md +3 -0
- package/recipes/pump/guide.en.md +17 -0
- package/recipes/pump/guide.ko.md +17 -0
- package/recipes/pump/models/default.json +1 -0
- package/recipes/pump/recipe.json +109 -0
- package/recipes/pump/spec.json +18 -0
- package/recipes/pump/thumbnail.png +0 -0
- package/recipes/pusher/build.mts +11 -0
- package/recipes/pusher/facts.md +3 -0
- package/recipes/pusher/guide.en.md +18 -0
- package/recipes/pusher/guide.ko.md +18 -0
- package/recipes/pusher/models/default.json +1 -0
- package/recipes/pusher/recipe.json +105 -0
- package/recipes/pusher/spec.json +45 -0
- package/recipes/pusher/thumbnail.png +0 -0
- package/recipes/robot-plinth/build.mts +9 -0
- package/recipes/robot-plinth/facts.md +3 -0
- package/recipes/robot-plinth/guide.en.md +17 -0
- package/recipes/robot-plinth/guide.ko.md +17 -0
- package/recipes/robot-plinth/models/default.json +1 -0
- package/recipes/robot-plinth/recipe.json +115 -0
- package/recipes/robot-plinth/spec.json +45 -0
- package/recipes/robot-plinth/thumbnail.png +0 -0
- package/recipes/roll-up-shutter/build.mts +17 -0
- package/recipes/roll-up-shutter/facts.md +3 -0
- package/recipes/roll-up-shutter/guide.en.md +18 -0
- package/recipes/roll-up-shutter/guide.ko.md +18 -0
- package/recipes/roll-up-shutter/models/default.json +1 -0
- package/recipes/roll-up-shutter/recipe.json +200 -0
- package/recipes/roll-up-shutter/spec.json +69 -0
- package/recipes/roll-up-shutter/thumbnail.png +0 -0
- package/recipes/roller-row/build.mts +18 -0
- package/recipes/roller-row/facts.md +20 -0
- package/recipes/roller-row/guide.en.md +21 -0
- package/recipes/roller-row/guide.ko.md +21 -0
- package/recipes/roller-row/models/default.json +1 -0
- package/recipes/roller-row/recipe.json +179 -0
- package/recipes/roller-row/spec.json +80 -0
- package/recipes/roller-row/thumbnail.png +0 -0
- package/recipes/room-shell/build.mts +16 -0
- package/recipes/room-shell/facts.md +3 -0
- package/recipes/room-shell/guide.en.md +18 -0
- package/recipes/room-shell/guide.ko.md +18 -0
- package/recipes/room-shell/models/default.json +1 -0
- package/recipes/room-shell/recipe.json +324 -0
- package/recipes/room-shell/spec.json +81 -0
- package/recipes/room-shell/thumbnail.png +0 -0
- package/recipes/rotating-beacon/build.mts +17 -0
- package/recipes/rotating-beacon/facts.md +3 -0
- package/recipes/rotating-beacon/guide.en.md +17 -0
- package/recipes/rotating-beacon/guide.ko.md +17 -0
- package/recipes/rotating-beacon/models/default.json +1 -0
- package/recipes/rotating-beacon/recipe.json +160 -0
- package/recipes/rotating-beacon/spec.json +18 -0
- package/recipes/rotating-beacon/thumbnail.png +0 -0
- package/recipes/safety-fence/build.mts +15 -0
- package/recipes/safety-fence/facts.md +3 -0
- package/recipes/safety-fence/guide.en.md +19 -0
- package/recipes/safety-fence/guide.ko.md +19 -0
- package/recipes/safety-fence/models/default.json +1 -0
- package/recipes/safety-fence/recipe.json +161 -0
- package/recipes/safety-fence/spec.json +80 -0
- package/recipes/safety-fence/thumbnail.png +0 -0
- package/recipes/safety-mat/build.mts +11 -0
- package/recipes/safety-mat/facts.md +3 -0
- package/recipes/safety-mat/guide.en.md +18 -0
- package/recipes/safety-mat/guide.ko.md +18 -0
- package/recipes/safety-mat/models/default.json +1 -0
- package/recipes/safety-mat/recipe.json +93 -0
- package/recipes/safety-mat/spec.json +44 -0
- package/recipes/safety-mat/thumbnail.png +0 -0
- package/recipes/safety-sign-stand/build.mts +16 -0
- package/recipes/safety-sign-stand/facts.md +3 -0
- package/recipes/safety-sign-stand/guide.en.md +16 -0
- package/recipes/safety-sign-stand/guide.ko.md +16 -0
- package/recipes/safety-sign-stand/models/default.json +1 -0
- package/recipes/safety-sign-stand/recipe.json +144 -0
- package/recipes/safety-sign-stand/spec.json +11 -0
- package/recipes/safety-sign-stand/thumbnail.png +0 -0
- package/recipes/scanner-mount/build.mts +10 -0
- package/recipes/scanner-mount/facts.md +3 -0
- package/recipes/scanner-mount/guide.en.md +16 -0
- package/recipes/scanner-mount/guide.ko.md +16 -0
- package/recipes/scanner-mount/models/default.json +1 -0
- package/recipes/scanner-mount/recipe.json +147 -0
- package/recipes/scanner-mount/spec.json +18 -0
- package/recipes/scanner-mount/thumbnail.png +0 -0
- package/recipes/selector-switch/build.mts +14 -0
- package/recipes/selector-switch/facts.md +3 -0
- package/recipes/selector-switch/guide.en.md +17 -0
- package/recipes/selector-switch/guide.ko.md +17 -0
- package/recipes/selector-switch/models/default.json +1 -0
- package/recipes/selector-switch/recipe.json +104 -0
- package/recipes/selector-switch/spec.json +11 -0
- package/recipes/selector-switch/thumbnail.png +0 -0
- package/recipes/shelf-tiers/build.mts +12 -0
- package/recipes/shelf-tiers/facts.md +3 -0
- package/recipes/shelf-tiers/guide.en.md +18 -0
- package/recipes/shelf-tiers/guide.ko.md +18 -0
- package/recipes/shelf-tiers/models/default.json +1 -0
- package/recipes/shelf-tiers/models/tiers=2.json +1 -0
- package/recipes/shelf-tiers/models/tiers=3.json +1 -0
- package/recipes/shelf-tiers/models/tiers=4.json +1 -0
- package/recipes/shelf-tiers/models/tiers=5.json +1 -0
- package/recipes/shelf-tiers/recipe.json +196 -0
- package/recipes/shelf-tiers/spec.json +64 -0
- package/recipes/shelf-tiers/thumbnail.png +0 -0
- package/recipes/side-guides/build.mts +12 -0
- package/recipes/side-guides/facts.md +3 -0
- package/recipes/side-guides/guide.en.md +18 -0
- package/recipes/side-guides/guide.ko.md +18 -0
- package/recipes/side-guides/models/default.json +1 -0
- package/recipes/side-guides/recipe.json +147 -0
- package/recipes/side-guides/spec.json +54 -0
- package/recipes/side-guides/thumbnail.png +0 -0
- package/recipes/sign-board/build.mts +11 -0
- package/recipes/sign-board/facts.md +3 -0
- package/recipes/sign-board/guide.en.md +18 -0
- package/recipes/sign-board/guide.ko.md +18 -0
- package/recipes/sign-board/models/default.json +1 -0
- package/recipes/sign-board/recipe.json +93 -0
- package/recipes/sign-board/spec.json +44 -0
- package/recipes/sign-board/thumbnail.png +0 -0
- package/recipes/signal-tower-3/build.mts +19 -0
- package/recipes/signal-tower-3/facts.md +3 -0
- package/recipes/signal-tower-3/guide.en.md +17 -0
- package/recipes/signal-tower-3/guide.ko.md +17 -0
- package/recipes/signal-tower-3/models/default.json +1 -0
- package/recipes/signal-tower-3/recipe.json +216 -0
- package/recipes/signal-tower-3/spec.json +19 -0
- package/recipes/signal-tower-3/thumbnail.png +0 -0
- package/recipes/sliding-door/build.mts +47 -0
- package/recipes/sliding-door/facts.md +26 -0
- package/recipes/sliding-door/guide.en.md +22 -0
- package/recipes/sliding-door/guide.ko.md +22 -0
- package/recipes/sliding-door/models/default.json +1 -0
- package/recipes/sliding-door/models/leaves=1,lamp=false.json +1 -0
- package/recipes/sliding-door/models/leaves=1,lamp=true.json +1 -0
- package/recipes/sliding-door/models/leaves=2,lamp=false.json +1 -0
- package/recipes/sliding-door/models/leaves=2,lamp=true.json +1 -0
- package/recipes/sliding-door/recipe.json +506 -0
- package/recipes/sliding-door/spec.json +26 -0
- package/recipes/sliding-door/thumbnail.png +0 -0
- package/recipes/stairs/build.mts +11 -0
- package/recipes/stairs/facts.md +3 -0
- package/recipes/stairs/guide.en.md +19 -0
- package/recipes/stairs/guide.ko.md +19 -0
- package/recipes/stairs/models/default.json +1 -0
- package/recipes/stairs/recipe.json +110 -0
- package/recipes/stairs/spec.json +94 -0
- package/recipes/stairs/thumbnail.png +0 -0
- package/recipes/status-lamp/build.mts +17 -0
- package/recipes/status-lamp/facts.md +3 -0
- package/recipes/status-lamp/guide.en.md +17 -0
- package/recipes/status-lamp/guide.ko.md +17 -0
- package/recipes/status-lamp/models/default.json +1 -0
- package/recipes/status-lamp/recipe.json +172 -0
- package/recipes/status-lamp/spec.json +18 -0
- package/recipes/status-lamp/thumbnail.png +0 -0
- package/recipes/stopper/build.mts +12 -0
- package/recipes/stopper/facts.md +3 -0
- package/recipes/stopper/guide.en.md +18 -0
- package/recipes/stopper/guide.ko.md +18 -0
- package/recipes/stopper/models/default.json +1 -0
- package/recipes/stopper/recipe.json +108 -0
- package/recipes/stopper/spec.json +45 -0
- package/recipes/stopper/thumbnail.png +0 -0
- package/recipes/suction-pads/build.mts +11 -0
- package/recipes/suction-pads/facts.md +3 -0
- package/recipes/suction-pads/guide.en.md +18 -0
- package/recipes/suction-pads/guide.ko.md +18 -0
- package/recipes/suction-pads/models/default.json +1 -0
- package/recipes/suction-pads/recipe.json +86 -0
- package/recipes/suction-pads/spec.json +45 -0
- package/recipes/suction-pads/thumbnail.png +0 -0
- package/recipes/tank/build.mts +12 -0
- package/recipes/tank/facts.md +3 -0
- package/recipes/tank/guide.en.md +18 -0
- package/recipes/tank/guide.ko.md +18 -0
- package/recipes/tank/models/default.json +1 -0
- package/recipes/tank/recipe.json +105 -0
- package/recipes/tank/spec.json +44 -0
- package/recipes/tank/thumbnail.png +0 -0
- package/recipes/telescopic-arm/build.mts +15 -0
- package/recipes/telescopic-arm/facts.md +3 -0
- package/recipes/telescopic-arm/guide.en.md +17 -0
- package/recipes/telescopic-arm/guide.ko.md +17 -0
- package/recipes/telescopic-arm/models/default.json +1 -0
- package/recipes/telescopic-arm/recipe.json +108 -0
- package/recipes/telescopic-arm/spec.json +18 -0
- package/recipes/telescopic-arm/thumbnail.png +0 -0
- package/recipes/toe-board/build.mts +11 -0
- package/recipes/toe-board/facts.md +3 -0
- package/recipes/toe-board/guide.en.md +18 -0
- package/recipes/toe-board/guide.ko.md +18 -0
- package/recipes/toe-board/models/default.json +1 -0
- package/recipes/toe-board/recipe.json +92 -0
- package/recipes/toe-board/spec.json +45 -0
- package/recipes/toe-board/thumbnail.png +0 -0
- package/recipes/tote/build.mts +10 -0
- package/recipes/tote/facts.md +3 -0
- package/recipes/tote/guide.en.md +18 -0
- package/recipes/tote/guide.ko.md +18 -0
- package/recipes/tote/models/default.json +1 -0
- package/recipes/tote/recipe.json +82 -0
- package/recipes/tote/spec.json +45 -0
- package/recipes/tote/thumbnail.png +0 -0
- package/recipes/traffic-cones/build.mts +15 -0
- package/recipes/traffic-cones/facts.md +3 -0
- package/recipes/traffic-cones/guide.en.md +18 -0
- package/recipes/traffic-cones/guide.ko.md +18 -0
- package/recipes/traffic-cones/models/default.json +1 -0
- package/recipes/traffic-cones/recipe.json +130 -0
- package/recipes/traffic-cones/spec.json +22 -0
- package/recipes/traffic-cones/thumbnail.png +0 -0
- package/recipes/transfer-belts/build.mts +14 -0
- package/recipes/transfer-belts/facts.md +3 -0
- package/recipes/transfer-belts/guide.en.md +18 -0
- package/recipes/transfer-belts/guide.ko.md +18 -0
- package/recipes/transfer-belts/models/default.json +1 -0
- package/recipes/transfer-belts/recipe.json +174 -0
- package/recipes/transfer-belts/spec.json +45 -0
- package/recipes/transfer-belts/thumbnail.png +0 -0
- package/recipes/tray-stack/build.mts +13 -0
- package/recipes/tray-stack/facts.md +3 -0
- package/recipes/tray-stack/guide.en.md +18 -0
- package/recipes/tray-stack/guide.ko.md +18 -0
- package/recipes/tray-stack/models/default.json +1 -0
- package/recipes/tray-stack/models/trays=3.json +1 -0
- package/recipes/tray-stack/models/trays=4.json +1 -0
- package/recipes/tray-stack/models/trays=5.json +1 -0
- package/recipes/tray-stack/recipe.json +289 -0
- package/recipes/tray-stack/spec.json +20 -0
- package/recipes/tray-stack/thumbnail.png +0 -0
- package/recipes/trough/build.mts +11 -0
- package/recipes/trough/facts.md +3 -0
- package/recipes/trough/guide.en.md +17 -0
- package/recipes/trough/guide.ko.md +17 -0
- package/recipes/trough/models/default.json +1 -0
- package/recipes/trough/recipe.json +75 -0
- package/recipes/trough/spec.json +18 -0
- package/recipes/trough/thumbnail.png +0 -0
- package/recipes/turntable/build.mts +15 -0
- package/recipes/turntable/facts.md +3 -0
- package/recipes/turntable/guide.en.md +18 -0
- package/recipes/turntable/guide.ko.md +18 -0
- package/recipes/turntable/models/default.json +1 -0
- package/recipes/turntable/recipe.json +140 -0
- package/recipes/turntable/spec.json +43 -0
- package/recipes/turntable/thumbnail.png +0 -0
- package/recipes/valve-handle/build.mts +17 -0
- package/recipes/valve-handle/facts.md +3 -0
- package/recipes/valve-handle/guide.en.md +17 -0
- package/recipes/valve-handle/guide.ko.md +17 -0
- package/recipes/valve-handle/models/default.json +1 -0
- package/recipes/valve-handle/recipe.json +149 -0
- package/recipes/valve-handle/spec.json +18 -0
- package/recipes/valve-handle/thumbnail.png +0 -0
- package/recipes/waste-bin/build.mts +10 -0
- package/recipes/waste-bin/facts.md +3 -0
- package/recipes/waste-bin/guide.en.md +17 -0
- package/recipes/waste-bin/guide.ko.md +17 -0
- package/recipes/waste-bin/models/default.json +1 -0
- package/recipes/waste-bin/recipe.json +82 -0
- package/recipes/waste-bin/spec.json +45 -0
- package/recipes/waste-bin/thumbnail.png +0 -0
- package/recipes/work-light/build.mts +18 -0
- package/recipes/work-light/facts.md +3 -0
- package/recipes/work-light/guide.en.md +17 -0
- package/recipes/work-light/guide.ko.md +17 -0
- package/recipes/work-light/models/default.json +1 -0
- package/recipes/work-light/recipe.json +162 -0
- package/recipes/work-light/spec.json +18 -0
- package/recipes/work-light/thumbnail.png +0 -0
- package/recipes/workbench-top/build.mts +12 -0
- package/recipes/workbench-top/facts.md +3 -0
- package/recipes/workbench-top/guide.en.md +18 -0
- package/recipes/workbench-top/guide.ko.md +18 -0
- package/recipes/workbench-top/models/default.json +1 -0
- package/recipes/workbench-top/recipe.json +99 -0
- package/recipes/workbench-top/spec.json +45 -0
- package/recipes/workbench-top/thumbnail.png +0 -0
- package/scripts/build-templates.mts +64 -0
- package/scripts/templates.test.mts +89 -0
- package/server/index.ts +6 -10
- package/server/routers/figure-thumbnail-router.ts +24 -0
- package/server/service/figure-recipe/figure-recipe-resolver.ts +28 -16
- package/server/service/figure-recipe/figure-recipe-templates.test.ts +47 -0
- package/server/service/figure-recipe/figure-recipe-templates.ts +70 -0
- package/server/service/figure-recipe/figure-recipe-type.ts +31 -0
- package/server/service/figure-recipe/index.ts +2 -4
- package/server/service/index.ts +4 -4
- package/dist-server/service/figure-recipe/figure-recipe-store.d.ts +0 -30
- package/dist-server/service/figure-recipe/figure-recipe-store.js +0 -79
- package/dist-server/service/figure-recipe/figure-recipe-store.js.map +0 -1
- package/dist-server/service/figure-recipe/figure-recipe.d.ts +0 -19
- package/dist-server/service/figure-recipe/figure-recipe.js +0 -67
- package/dist-server/service/figure-recipe/figure-recipe.js.map +0 -1
- package/server/service/figure-recipe/figure-recipe-db.test.ts +0 -103
- package/server/service/figure-recipe/figure-recipe-store.ts +0 -75
- package/server/service/figure-recipe/figure-recipe.ts +0 -51
package/dist-server/index.js
CHANGED
|
@@ -13,18 +13,13 @@ require("./routes.js");
|
|
|
13
13
|
const figure_tools_js_1 = require("./service/figure/figure-tools.js");
|
|
14
14
|
(0, figure_tools_js_1.registerFigureToolCategories)();
|
|
15
15
|
/*
|
|
16
|
-
* The
|
|
17
|
-
*
|
|
16
|
+
* The recipe templates are read once at start (ADR-0095, amended): what was served, and any file whose form is wrong,
|
|
17
|
+
* said here rather than found by a person as a missing template.
|
|
18
18
|
*/
|
|
19
|
-
const
|
|
20
|
-
process.on('bootstrap-module-start',
|
|
21
|
-
|
|
22
|
-
|
|
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
|
-
}
|
|
19
|
+
const figure_recipe_templates_js_1 = require("./service/figure-recipe/figure-recipe-templates.js");
|
|
20
|
+
process.on('bootstrap-module-start', () => {
|
|
21
|
+
const { templates, refused } = (0, figure_recipe_templates_js_1.recipeTemplates)();
|
|
22
|
+
console.log(`[figure-service:bootstrap] recipe templates ${templates.length}${refused.length ? `, left out: ${refused.join(' | ')}` : ''}`);
|
|
28
23
|
});
|
|
29
24
|
tslib_1.__exportStar(require("./service/index.js"), exports);
|
|
30
25
|
tslib_1.__exportStar(require("./migrations/index.js"), exports);
|
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;;;GAGG;AACH,
|
|
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,mGAAoF;AACpF,OAAO,CAAC,EAAE,CAAC,wBAA+B,EAAE,GAAG,EAAE;IAC/C,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,GAAG,IAAA,4CAAe,GAAE,CAAA;IAChD,OAAO,CAAC,GAAG,CAAC,+CAA+C,SAAS,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,eAAe,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAA;AAC7I,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 recipe templates are read once at start (ADR-0095, amended): what was served, and any file whose form is wrong,\n * said here rather than found by a person as a missing template.\n */\nimport { recipeTemplates } from './service/figure-recipe/figure-recipe-templates.js'\nprocess.on('bootstrap-module-start' as any, () => {\n const { templates, refused } = recipeTemplates()\n console.log(`[figure-service:bootstrap] recipe templates ${templates.length}${refused.length ? `, left out: ${refused.join(' | ')}` : ''}`)\n})\n\nexport * from './service/index.js'\nexport * from './migrations/index.js'\nexport { registerFigureToolCategories } from './service/figure/figure-tools.js'\n"]}
|
|
@@ -6,7 +6,9 @@ const koa_router_1 = tslib_1.__importDefault(require("koa-router"));
|
|
|
6
6
|
const typeorm_1 = require("typeorm");
|
|
7
7
|
const auth_base_1 = require("@things-factory/auth-base");
|
|
8
8
|
const shell_1 = require("@things-factory/shell");
|
|
9
|
+
const fs_1 = require("fs");
|
|
9
10
|
const figure_js_1 = require("../service/figure/figure.js");
|
|
11
|
+
const figure_recipe_templates_js_1 = require("../service/figure-recipe/figure-recipe-templates.js");
|
|
10
12
|
/**
|
|
11
13
|
* 썸네일을 **그림으로** 내보내는 길.
|
|
12
14
|
*
|
|
@@ -90,4 +92,24 @@ exports.figureThumbnailRouter.get('/figure-thumbnail/:id', async (context, next)
|
|
|
90
92
|
}
|
|
91
93
|
context.body = decoded.buffer;
|
|
92
94
|
});
|
|
95
|
+
/**
|
|
96
|
+
* A recipe template's thumbnail (ADR-0095 amended): the file drawn from its model, served behind the same door as the
|
|
97
|
+
* templates themselves. The file changes only with a release, so a day's private cache is enough.
|
|
98
|
+
*/
|
|
99
|
+
exports.figureThumbnailRouter.get('/figure-recipe-thumbnail/:name', async (context) => {
|
|
100
|
+
const { domain, user, unsafeIP, prohibitedPrivileges } = context.state;
|
|
101
|
+
const allowed = await (0, auth_base_1.checkPermission)({ category: 'figure', privilege: 'query', owner: true }, user, domain, unsafeIP, prohibitedPrivileges);
|
|
102
|
+
if (!allowed) {
|
|
103
|
+
context.status = 403;
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
const template = (0, figure_recipe_templates_js_1.recipeTemplates)().templates.find(t => t.recipe.name === context.params.name);
|
|
107
|
+
if (!template?.thumbnail) {
|
|
108
|
+
context.status = 404;
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
context.type = 'image/png';
|
|
112
|
+
context.set('Cache-Control', 'private, max-age=86400');
|
|
113
|
+
context.body = (0, fs_1.readFileSync)(template.thumbnail);
|
|
114
|
+
});
|
|
93
115
|
//# sourceMappingURL=figure-thumbnail-router.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"figure-thumbnail-router.js","sourceRoot":"","sources":["../../server/routers/figure-thumbnail-router.ts"],"names":[],"mappings":";;;;AAAA,oEAA+B;AAC/B,qCAA4B;AAE5B,yDAA2D;AAC3D,iDAAqD;AAErD,2DAAoD;
|
|
1
|
+
{"version":3,"file":"figure-thumbnail-router.js","sourceRoot":"","sources":["../../server/routers/figure-thumbnail-router.ts"],"names":[],"mappings":"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","sourcesContent":["import Router from 'koa-router'\nimport { In } from 'typeorm'\n\nimport { checkPermission } from '@things-factory/auth-base'\nimport { getRepository } from '@things-factory/shell'\n\nimport { readFileSync } from 'fs'\n\nimport { Figure } from '../service/figure/figure.js'\nimport { recipeTemplates } from '../service/figure-recipe/figure-recipe-templates.js'\n\n/**\n * 썸네일을 **그림으로** 내보내는 길.\n *\n * ## 왜 필요한가\n *\n * 썸네일은 base64 문자열로 칸에 들어 있다(`Board.thumbnail` 과 같은 방식). 그것을 목록 질의가\n * 함께 실어 오면 카탈로그를 열 때마다 그림 전부가 JSON 안에 담겨 다시 온다 — data URL 은\n * 브라우저가 캐시할 수 없다. [확인함] 표본 14개에 227KB, 한 장 최대 20KB.\n *\n * 그림으로 내보내면 브라우저가 캐시하고, 부르는 쪽이 `?v=thumbnailUpdatedAt` 을 붙이므로 그림이\n * 다시 만들어진 것만 다시 받는다. 목록 질의에서는 `thumbnail` 을 아예 고르지 않는다.\n *\n * ## board 를 베끼면서 고친 것 셋\n *\n * `standalone-board-service-router` 의 `/thumbnail/:id` 가 본이지만 그대로 두면 안 되는 것들이 있다.\n *\n * 1. **길 이름이 겹친다.** 이 앱은 board 도 함께 싣는다(메뉴가 board-ui 를 끌어온다).\n * `/thumbnail/:id` 로 두면 먼저 등록된 쪽이 이기고, 남의 표에서 id 를 찾아 404 를 낸다.\n * 2. **행 전체를 읽는다.** board 는 `findOneBy` 로 행을 다 읽는다. figure 행에는 정본(`source`)이\n * 붙어 있어, 그림 한 장에 정본까지 읽게 된다. 필요한 칸만 고른다.\n * 3. **png 로 못 박는다.** figure 썸네일은 webp 다(모델러가 그렇게 만든다). data URL 이 스스로\n * 말하는 형식을 쓴다 — 못 박으면 브라우저가 확장자와 다른 바이트를 받는다.\n */\nexport const figureThumbnailRouter = new Router()\n\n/** `data:image/webp;base64,....` → 형식과 바이트. 아니면 undefined. */\nfunction decodeDataUrl(dataUrl: string): { type: string; buffer: Buffer } | undefined {\n const matched = /^data:([^;,]+);base64,(.*)$/s.exec(dataUrl)\n if (!matched) {\n return undefined\n }\n\n return { type: matched[1], buffer: Buffer.from(matched[2], 'base64') }\n}\n\nfigureThumbnailRouter.get('/figure-thumbnail/:id', async (context, next) => {\n const { domain, user, unsafeIP, prohibitedPrivileges } = context.state\n\n /*\n **질의와 같은 문을 쓴다.**\n\n `User.hasPrivilege('query','figure',…)` 만 보면 안 된다 — figure 질의는\n `@privilege(category: \"figure\", privilege: \"query\", domainOwnerGranted: true)` 로 선언되어 있고,\n 도메인 소유자는 `figure:query` 권한 줄이 없어도 통과한다. 그 허용을 여기서 빼면 목록은 보이는데\n 그림만 403 이 되어, 화면은 「그림이 아직 없다」고 거짓말한다. [확인함] 실제로 카드 14장이 전부\n 403 이었다.\n\n 조건을 손으로 다시 적지 않고 지시자가 쓰는 함수를 그대로 쓴다. 선언이 바뀌면 여기도 함께 바뀐다.\n */\n const allowed = await checkPermission(\n { category: 'figure', privilege: 'query', owner: true },\n user,\n domain,\n unsafeIP,\n prohibitedPrivileges\n )\n\n if (!allowed) {\n context.status = 403\n return\n }\n\n const { id } = context.params\n\n /*\n 읽기는 부모 도메인까지 본다 — `figure` 질의와 같은 범위다. 물려받은 형상을 목록에는 보여 주고\n 그림만 404 를 내면, 화면은 「그림이 아직 없다」고 거짓말하게 된다.\n */\n const found = await getRepository(Figure).findOne({\n where: { domain: { id: In([domain.id, domain.parentId].filter(Boolean)) }, id },\n select: { id: true, thumbnail: true, thumbnailUpdatedAt: true }\n })\n\n const decoded = found?.thumbnail ? decodeDataUrl(found.thumbnail) : undefined\n\n if (!decoded) {\n context.status = 404\n return\n }\n\n /*\n **개인 캐시만 허락한다.** 이 그림은 권한을 본 뒤에 내주는 것이므로 공용 캐시(프록시)에 남으면\n 안 된다. 부르는 쪽이 `?v=` 로 판을 가리므로 오래 두어도 낡은 그림이 남지 않고, `v` 없이 부른\n 경우를 위해 시각을 함께 실어 다시 물어볼 수 있게 한다.\n */\n const stamp = found!.thumbnailUpdatedAt\n\n context.type = decoded.type\n context.set('Cache-Control', 'private, max-age=31536000')\n if (stamp) {\n context.set('Last-Modified', new Date(stamp).toUTCString())\n context.set('ETag', `\"${new Date(stamp).getTime()}\"`)\n\n /* 브라우저가 가진 것이 아직 그것이면 바이트를 보내지 않는다. */\n if (context.fresh) {\n context.status = 304\n return\n }\n }\n\n context.body = decoded.buffer\n})\n\n/**\n * A recipe template's thumbnail (ADR-0095 amended): the file drawn from its model, served behind the same door as the\n * templates themselves. The file changes only with a release, so a day's private cache is enough.\n */\nfigureThumbnailRouter.get('/figure-recipe-thumbnail/:name', async context => {\n const { domain, user, unsafeIP, prohibitedPrivileges } = context.state\n const allowed = await checkPermission({ category: 'figure', privilege: 'query', owner: true }, user, domain, unsafeIP, prohibitedPrivileges)\n if (!allowed) {\n context.status = 403\n return\n }\n const template = recipeTemplates().templates.find(t => t.recipe.name === context.params.name)\n if (!template?.thumbnail) {\n context.status = 404\n return\n }\n context.type = 'image/png'\n context.set('Cache-Control', 'private, max-age=86400')\n context.body = readFileSync(template.thumbnail)\n})\n"]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export declare class
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import { FigureRecipeTemplate } from './figure-recipe-type.js';
|
|
2
|
+
export declare class FigureRecipeTemplateQuery {
|
|
3
|
+
figureRecipeTemplates(lang: string): FigureRecipeTemplate[];
|
|
4
|
+
figureRecipeTemplate(name: string, lang: string): FigureRecipeTemplate | null;
|
|
5
5
|
}
|
|
@@ -1,41 +1,51 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.FigureRecipeTemplateQuery = void 0;
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
5
|
const type_graphql_1 = require("type-graphql");
|
|
6
6
|
const shell_1 = require("@things-factory/shell");
|
|
7
|
-
const
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
7
|
+
const figure_recipe_type_js_1 = require("./figure-recipe-type.js");
|
|
8
|
+
const figure_recipe_templates_js_1 = require("./figure-recipe-templates.js");
|
|
9
|
+
const view = (t, lang, withGuide) => ({
|
|
10
|
+
name: t.recipe.name,
|
|
11
|
+
category: t.category,
|
|
12
|
+
tags: t.tags,
|
|
13
|
+
target: t.recipe.target,
|
|
14
|
+
title: (0, figure_recipe_templates_js_1.inLanguage)(t.recipe.title, lang),
|
|
15
|
+
description: (0, figure_recipe_templates_js_1.inLanguage)(t.recipe.description, lang),
|
|
16
|
+
source: JSON.stringify(t.recipe),
|
|
17
|
+
...(withGuide ? { guide: (0, figure_recipe_templates_js_1.inLanguage)(t.guides, lang) } : {}),
|
|
18
|
+
hasThumbnail: !!t.thumbnail
|
|
19
|
+
});
|
|
20
|
+
let FigureRecipeTemplateQuery = class FigureRecipeTemplateQuery {
|
|
21
|
+
figureRecipeTemplates(lang) {
|
|
22
|
+
return (0, figure_recipe_templates_js_1.recipeTemplates)().templates.map(t => view(t, lang, false));
|
|
12
23
|
}
|
|
13
|
-
|
|
14
|
-
|
|
24
|
+
figureRecipeTemplate(name, lang) {
|
|
25
|
+
const t = (0, figure_recipe_templates_js_1.recipeTemplates)().templates.find(one => one.recipe.name === name);
|
|
26
|
+
return t ? view(t, lang, true) : null;
|
|
15
27
|
}
|
|
16
28
|
};
|
|
17
|
-
exports.
|
|
29
|
+
exports.FigureRecipeTemplateQuery = FigureRecipeTemplateQuery;
|
|
18
30
|
tslib_1.__decorate([
|
|
19
31
|
(0, type_graphql_1.Directive)('@privilege(category: "figure", privilege: "query", domainOwnerGranted: true)'),
|
|
20
|
-
(0, type_graphql_1.Query)(returns => [
|
|
21
|
-
tslib_1.__param(0, (0, type_graphql_1.Arg)('
|
|
22
|
-
tslib_1.__param(1, (0, type_graphql_1.Ctx)()),
|
|
32
|
+
(0, type_graphql_1.Query)(returns => [figure_recipe_type_js_1.FigureRecipeTemplate], { description: 'The recipe templates the product ships, in the language asked. Guides are left out of the list.' }),
|
|
33
|
+
tslib_1.__param(0, (0, type_graphql_1.Arg)('lang', { nullable: true, description: 'The language of the titles (ko, en, …).' })),
|
|
23
34
|
tslib_1.__metadata("design:type", Function),
|
|
24
|
-
tslib_1.__metadata("design:paramtypes", [
|
|
25
|
-
tslib_1.__metadata("design:returntype",
|
|
26
|
-
],
|
|
35
|
+
tslib_1.__metadata("design:paramtypes", [String]),
|
|
36
|
+
tslib_1.__metadata("design:returntype", Array)
|
|
37
|
+
], FigureRecipeTemplateQuery.prototype, "figureRecipeTemplates", null);
|
|
27
38
|
tslib_1.__decorate([
|
|
28
|
-
(0, type_graphql_1.Directive)('@privilege(category: "figure", privilege: "
|
|
29
|
-
(0, type_graphql_1.
|
|
30
|
-
tslib_1.__param(0, (0, type_graphql_1.Arg)('
|
|
31
|
-
tslib_1.__param(1, (0, type_graphql_1.Arg)('
|
|
32
|
-
tslib_1.__param(2, (0, type_graphql_1.Ctx)()),
|
|
39
|
+
(0, type_graphql_1.Directive)('@privilege(category: "figure", privilege: "query", domainOwnerGranted: true)'),
|
|
40
|
+
(0, type_graphql_1.Query)(returns => figure_recipe_type_js_1.FigureRecipeTemplate, { nullable: true, description: 'One recipe template with its guide, in the language asked.' }),
|
|
41
|
+
tslib_1.__param(0, (0, type_graphql_1.Arg)('name', { description: 'The template name.' })),
|
|
42
|
+
tslib_1.__param(1, (0, type_graphql_1.Arg)('lang', { nullable: true, description: 'The language of the words (ko, en, …).' })),
|
|
33
43
|
tslib_1.__metadata("design:type", Function),
|
|
34
|
-
tslib_1.__metadata("design:paramtypes", [String, String
|
|
35
|
-
tslib_1.__metadata("design:returntype",
|
|
36
|
-
],
|
|
37
|
-
exports.
|
|
38
|
-
(0, type_graphql_1.Resolver)(
|
|
44
|
+
tslib_1.__metadata("design:paramtypes", [String, String]),
|
|
45
|
+
tslib_1.__metadata("design:returntype", figure_recipe_type_js_1.FigureRecipeTemplate)
|
|
46
|
+
], FigureRecipeTemplateQuery.prototype, "figureRecipeTemplate", null);
|
|
47
|
+
exports.FigureRecipeTemplateQuery = FigureRecipeTemplateQuery = tslib_1.__decorate([
|
|
48
|
+
(0, type_graphql_1.Resolver)(figure_recipe_type_js_1.FigureRecipeTemplate),
|
|
39
49
|
(0, type_graphql_1.UseMiddleware)(shell_1.SpeakRefusals)
|
|
40
|
-
],
|
|
50
|
+
], FigureRecipeTemplateQuery);
|
|
41
51
|
//# sourceMappingURL=figure-recipe-resolver.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"figure-recipe-resolver.js","sourceRoot":"","sources":["../../../server/service/figure-recipe/figure-recipe-resolver.ts"],"names":[],"mappings":";;;;AAAA,+
|
|
1
|
+
{"version":3,"file":"figure-recipe-resolver.js","sourceRoot":"","sources":["../../../server/service/figure-recipe/figure-recipe-resolver.ts"],"names":[],"mappings":";;;;AAAA,+CAA6E;AAE7E,iDAAqD;AAErD,mEAA8D;AAC9D,6EAA+F;AAE/F,MAAM,IAAI,GAAG,CAAC,CAAiB,EAAE,IAAwB,EAAE,SAAkB,EAAwB,EAAE,CAAC,CAAC;IACvG,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,IAAI;IACnB,QAAQ,EAAE,CAAC,CAAC,QAAQ;IACpB,IAAI,EAAE,CAAC,CAAC,IAAI;IACZ,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,MAAM;IACvB,KAAK,EAAE,IAAA,uCAAU,EAAC,CAAC,CAAC,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC;IACvC,WAAW,EAAE,IAAA,uCAAU,EAAC,CAAC,CAAC,MAAM,CAAC,WAAW,EAAE,IAAI,CAAC;IACnD,MAAM,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC;IAChC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,IAAA,uCAAU,EAAC,CAAC,CAAC,MAAM,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IAC3D,YAAY,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS;CAC5B,CAAC,CAAA;AAIK,IAAM,yBAAyB,GAA/B,MAAM,yBAAyB;IAGpC,qBAAqB,CAA0F,IAAY;QACzH,OAAO,IAAA,4CAAe,GAAE,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC,CAAA;IACnE,CAAC;IAID,oBAAoB,CACkC,IAAY,EACwB,IAAY;QAEpG,MAAM,CAAC,GAAG,IAAA,4CAAe,GAAE,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,KAAK,IAAI,CAAC,CAAA;QAC3E,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;IACvC,CAAC;CACF,CAAA;AAhBY,8DAAyB;AAGpC;IAFC,IAAA,wBAAS,EAAC,8EAA8E,CAAC;IACzF,IAAA,oBAAK,EAAC,OAAO,CAAC,EAAE,CAAC,CAAC,4CAAoB,CAAC,EAAE,EAAE,WAAW,EAAE,iGAAiG,EAAE,CAAC;IACtI,mBAAA,IAAA,kBAAG,EAAC,MAAM,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,yCAAyC,EAAE,CAAC,CAAA;;;;sEAE7G;AAID;IAFC,IAAA,wBAAS,EAAC,8EAA8E,CAAC;IACzF,IAAA,oBAAK,EAAC,OAAO,CAAC,EAAE,CAAC,4CAAoB,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,4DAA4D,EAAE,CAAC;IAEnI,mBAAA,IAAA,kBAAG,EAAC,MAAM,EAAE,EAAE,WAAW,EAAE,oBAAoB,EAAE,CAAC,CAAA;IAClD,mBAAA,IAAA,kBAAG,EAAC,MAAM,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,wCAAwC,EAAE,CAAC,CAAA;;;4CACtF,4CAAoB;qEAGtB;oCAfU,yBAAyB;IAFrC,IAAA,uBAAQ,EAAC,4CAAoB,CAAC;IAC9B,IAAA,4BAAa,EAAC,qBAAa,CAAC;GAChB,yBAAyB,CAgBrC","sourcesContent":["import { Arg, Directive, Query, Resolver, UseMiddleware } from 'type-graphql'\n\nimport { SpeakRefusals } from '@things-factory/shell'\n\nimport { FigureRecipeTemplate } from './figure-recipe-type.js'\nimport { inLanguage, recipeTemplates, type RecipeTemplate } from './figure-recipe-templates.js'\n\nconst view = (t: RecipeTemplate, lang: string | undefined, withGuide: boolean): FigureRecipeTemplate => ({\n name: t.recipe.name,\n category: t.category,\n tags: t.tags,\n target: t.recipe.target,\n title: inLanguage(t.recipe.title, lang),\n description: inLanguage(t.recipe.description, lang),\n source: JSON.stringify(t.recipe),\n ...(withGuide ? { guide: inLanguage(t.guides, lang) } : {}),\n hasThumbnail: !!t.thumbnail\n})\n\n@Resolver(FigureRecipeTemplate)\n@UseMiddleware(SpeakRefusals)\nexport class FigureRecipeTemplateQuery {\n @Directive('@privilege(category: \"figure\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(returns => [FigureRecipeTemplate], { description: 'The recipe templates the product ships, in the language asked. Guides are left out of the list.' })\n figureRecipeTemplates(@Arg('lang', { nullable: true, description: 'The language of the titles (ko, en, …).' }) lang: string): FigureRecipeTemplate[] {\n return recipeTemplates().templates.map(t => view(t, lang, false))\n }\n\n @Directive('@privilege(category: \"figure\", privilege: \"query\", domainOwnerGranted: true)')\n @Query(returns => FigureRecipeTemplate, { nullable: true, description: 'One recipe template with its guide, in the language asked.' })\n figureRecipeTemplate(\n @Arg('name', { description: 'The template name.' }) name: string,\n @Arg('lang', { nullable: true, description: 'The language of the words (ko, en, …).' }) lang: string\n ): FigureRecipeTemplate | null {\n const t = recipeTemplates().templates.find(one => one.recipe.name === name)\n return t ? view(t, lang, true) : null\n }\n}\n"]}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { V3Recipe } from '@hatiolab/figure-model';
|
|
2
|
+
/**
|
|
3
|
+
* The recipe templates the product ships (ADR-0095, amended 2026-09-26): static files, served, not managed.
|
|
4
|
+
*
|
|
5
|
+
* recipes/<name>/recipe.json the command list, its parameters, category, tags, titles
|
|
6
|
+
* recipes/<name>/guide.<lang>.md how to use it, per language (English stands in for a missing one)
|
|
7
|
+
* recipes/<name>/thumbnail.png drawn by a script from the recipe put into the test room
|
|
8
|
+
*
|
|
9
|
+
* There is no table and no screen that changes them: a template is added or changed as a file, with the code. The
|
|
10
|
+
* start reads their form only; putting each into the test room is the tests' work (`figure-recipe-templates.test.ts`).
|
|
11
|
+
*/
|
|
12
|
+
export interface RecipeTemplate {
|
|
13
|
+
recipe: V3Recipe;
|
|
14
|
+
category: string;
|
|
15
|
+
tags: string[];
|
|
16
|
+
/** Guides by language code, as written. */
|
|
17
|
+
guides: Record<string, string>;
|
|
18
|
+
thumbnail: string | null;
|
|
19
|
+
}
|
|
20
|
+
/** The folder the templates are in: `recipes/` at the package root, beside `server/` and `dist-server/`. */
|
|
21
|
+
export declare const RECIPE_DIR: string;
|
|
22
|
+
/** Every template, read once. One whose form is wrong is left out and named, not half served. */
|
|
23
|
+
export declare function recipeTemplates(dir?: string): {
|
|
24
|
+
templates: RecipeTemplate[];
|
|
25
|
+
refused: string[];
|
|
26
|
+
};
|
|
27
|
+
/** A word in the language asked: that language, its base (`ko` for `ko-KR`), English, then the first there is. */
|
|
28
|
+
export declare function inLanguage(words: Record<string, string> | undefined, lang: string | undefined): string;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RECIPE_DIR = void 0;
|
|
4
|
+
exports.recipeTemplates = recipeTemplates;
|
|
5
|
+
exports.inLanguage = inLanguage;
|
|
6
|
+
const fs_1 = require("fs");
|
|
7
|
+
const path_1 = require("path");
|
|
8
|
+
const figure_model_1 = require("@hatiolab/figure-model");
|
|
9
|
+
/** The folder the templates are in: `recipes/` at the package root, beside `server/` and `dist-server/`. */
|
|
10
|
+
exports.RECIPE_DIR = (0, path_1.resolve)(__dirname, '..', '..', '..', 'recipes');
|
|
11
|
+
let loaded = null;
|
|
12
|
+
/** Every template, read once. One whose form is wrong is left out and named, not half served. */
|
|
13
|
+
function recipeTemplates(dir = exports.RECIPE_DIR) {
|
|
14
|
+
if (loaded && dir === exports.RECIPE_DIR)
|
|
15
|
+
return loaded;
|
|
16
|
+
const templates = [];
|
|
17
|
+
const refused = [];
|
|
18
|
+
/* A folder starting with _ holds what the models are built with, not a template. */
|
|
19
|
+
const folders = (0, fs_1.existsSync)(dir) ? (0, fs_1.readdirSync)(dir, { withFileTypes: true }).filter(e => e.isDirectory() && !e.name.startsWith('_')).map(e => e.name).sort() : [];
|
|
20
|
+
for (const folder of folders) {
|
|
21
|
+
const at = (0, path_1.join)(dir, folder);
|
|
22
|
+
try {
|
|
23
|
+
const raw = JSON.parse((0, fs_1.readFileSync)((0, path_1.join)(at, 'recipe.json'), 'utf-8'));
|
|
24
|
+
const recipe = (0, figure_model_1.parseV3Recipe)(raw);
|
|
25
|
+
if (recipe.name !== folder)
|
|
26
|
+
throw new Error(`the recipe is named ${recipe.name}, its folder ${folder}`);
|
|
27
|
+
const guides = {};
|
|
28
|
+
for (const file of (0, fs_1.readdirSync)(at)) {
|
|
29
|
+
const lang = /^guide\.([a-zA-Z-]+)\.md$/.exec(file)?.[1];
|
|
30
|
+
if (lang)
|
|
31
|
+
guides[lang] = (0, fs_1.readFileSync)((0, path_1.join)(at, file), 'utf-8');
|
|
32
|
+
}
|
|
33
|
+
templates.push({
|
|
34
|
+
recipe,
|
|
35
|
+
category: typeof raw.category === 'string' ? raw.category : 'other',
|
|
36
|
+
tags: Array.isArray(raw.tags) ? raw.tags.filter((t) => typeof t === 'string') : [],
|
|
37
|
+
guides,
|
|
38
|
+
thumbnail: (0, fs_1.existsSync)((0, path_1.join)(at, 'thumbnail.png')) ? (0, path_1.join)(at, 'thumbnail.png') : null
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
catch (error) {
|
|
42
|
+
refused.push(`${folder}: ${error instanceof Error ? error.message : String(error)}`);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
const result = { templates, refused };
|
|
46
|
+
if (dir === exports.RECIPE_DIR)
|
|
47
|
+
loaded = result;
|
|
48
|
+
return result;
|
|
49
|
+
}
|
|
50
|
+
/** A word in the language asked: that language, its base (`ko` for `ko-KR`), English, then the first there is. */
|
|
51
|
+
function inLanguage(words, lang) {
|
|
52
|
+
if (!words)
|
|
53
|
+
return '';
|
|
54
|
+
const asked = lang || 'en';
|
|
55
|
+
return words[asked] ?? words[asked.split('-')[0]] ?? words.en ?? Object.values(words)[0] ?? '';
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=figure-recipe-templates.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"figure-recipe-templates.js","sourceRoot":"","sources":["../../../server/service/figure-recipe/figure-recipe-templates.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync, readdirSync, readFileSync } from 'fs'\nimport { join, resolve } from 'path'\n\nimport { parseV3Recipe } from '@hatiolab/figure-model'\nimport type { V3Recipe } from '@hatiolab/figure-model'\n\n/**\n * The recipe templates the product ships (ADR-0095, amended 2026-09-26): static files, served, not managed.\n *\n * recipes/<name>/recipe.json the command list, its parameters, category, tags, titles\n * recipes/<name>/guide.<lang>.md how to use it, per language (English stands in for a missing one)\n * recipes/<name>/thumbnail.png drawn by a script from the recipe put into the test room\n *\n * There is no table and no screen that changes them: a template is added or changed as a file, with the code. The\n * start reads their form only; putting each into the test room is the tests' work (`figure-recipe-templates.test.ts`).\n */\nexport interface RecipeTemplate {\n recipe: V3Recipe\n category: string\n tags: string[]\n /** Guides by language code, as written. */\n guides: Record<string, string>\n thumbnail: string | null\n}\n\n/** The folder the templates are in: `recipes/` at the package root, beside `server/` and `dist-server/`. */\nexport const RECIPE_DIR = resolve(__dirname, '..', '..', '..', 'recipes')\n\nlet loaded: { templates: RecipeTemplate[]; refused: string[] } | null = null\n\n/** Every template, read once. One whose form is wrong is left out and named, not half served. */\nexport function recipeTemplates(dir: string = RECIPE_DIR): { templates: RecipeTemplate[]; refused: string[] } {\n if (loaded && dir === RECIPE_DIR) return loaded\n const templates: RecipeTemplate[] = []\n const refused: string[] = []\n /* A folder starting with _ holds what the models are built with, not a template. */\n const folders = existsSync(dir) ? readdirSync(dir, { withFileTypes: true }).filter(e => e.isDirectory() && !e.name.startsWith('_')).map(e => e.name).sort() : []\n for (const folder of folders) {\n const at = join(dir, folder)\n try {\n const raw = JSON.parse(readFileSync(join(at, 'recipe.json'), 'utf-8'))\n const recipe = parseV3Recipe(raw)\n if (recipe.name !== folder) throw new Error(`the recipe is named ${recipe.name}, its folder ${folder}`)\n const guides: Record<string, string> = {}\n for (const file of readdirSync(at)) {\n const lang = /^guide\\.([a-zA-Z-]+)\\.md$/.exec(file)?.[1]\n if (lang) guides[lang] = readFileSync(join(at, file), 'utf-8')\n }\n templates.push({\n recipe,\n category: typeof raw.category === 'string' ? raw.category : 'other',\n tags: Array.isArray(raw.tags) ? raw.tags.filter((t: unknown) => typeof t === 'string') : [],\n guides,\n thumbnail: existsSync(join(at, 'thumbnail.png')) ? join(at, 'thumbnail.png') : null\n })\n } catch (error) {\n refused.push(`${folder}: ${error instanceof Error ? error.message : String(error)}`)\n }\n }\n const result = { templates, refused }\n if (dir === RECIPE_DIR) loaded = result\n return result\n}\n\n/** A word in the language asked: that language, its base (`ko` for `ko-KR`), English, then the first there is. */\nexport function inLanguage(words: Record<string, string> | undefined, lang: string | undefined): string {\n if (!words) return ''\n const asked = lang || 'en'\n return words[asked] ?? words[asked.split('-')[0]!] ?? words.en ?? Object.values(words)[0] ?? ''\n}\n"]}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.FigureRecipeTemplate = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const type_graphql_1 = require("type-graphql");
|
|
6
|
+
let FigureRecipeTemplate = class FigureRecipeTemplate {
|
|
7
|
+
};
|
|
8
|
+
exports.FigureRecipeTemplate = FigureRecipeTemplate;
|
|
9
|
+
tslib_1.__decorate([
|
|
10
|
+
(0, type_graphql_1.Field)({ description: 'The template name: lower case, digits and hyphens.' }),
|
|
11
|
+
tslib_1.__metadata("design:type", String)
|
|
12
|
+
], FigureRecipeTemplate.prototype, "name", void 0);
|
|
13
|
+
tslib_1.__decorate([
|
|
14
|
+
(0, type_graphql_1.Field)({ description: 'The category it is listed under (door, conveyor, …).' }),
|
|
15
|
+
tslib_1.__metadata("design:type", String)
|
|
16
|
+
], FigureRecipeTemplate.prototype, "category", void 0);
|
|
17
|
+
tslib_1.__decorate([
|
|
18
|
+
(0, type_graphql_1.Field)(type => [String], { description: 'Words it is found by.' }),
|
|
19
|
+
tslib_1.__metadata("design:type", Array)
|
|
20
|
+
], FigureRecipeTemplate.prototype, "tags", void 0);
|
|
21
|
+
tslib_1.__decorate([
|
|
22
|
+
(0, type_graphql_1.Field)({ description: "'part' when it is put onto a chosen part, 'figure' when onto the whole figure." }),
|
|
23
|
+
tslib_1.__metadata("design:type", String)
|
|
24
|
+
], FigureRecipeTemplate.prototype, "target", void 0);
|
|
25
|
+
tslib_1.__decorate([
|
|
26
|
+
(0, type_graphql_1.Field)({ description: 'Its title in the language asked (English stands in).' }),
|
|
27
|
+
tslib_1.__metadata("design:type", String)
|
|
28
|
+
], FigureRecipeTemplate.prototype, "title", void 0);
|
|
29
|
+
tslib_1.__decorate([
|
|
30
|
+
(0, type_graphql_1.Field)({ description: 'Its one-line description in the language asked (English stands in).' }),
|
|
31
|
+
tslib_1.__metadata("design:type", String)
|
|
32
|
+
], FigureRecipeTemplate.prototype, "description", void 0);
|
|
33
|
+
tslib_1.__decorate([
|
|
34
|
+
(0, type_graphql_1.Field)({ description: 'The recipe JSON (figure-model V3Recipe), as the modeller applies it.' }),
|
|
35
|
+
tslib_1.__metadata("design:type", String)
|
|
36
|
+
], FigureRecipeTemplate.prototype, "source", void 0);
|
|
37
|
+
tslib_1.__decorate([
|
|
38
|
+
(0, type_graphql_1.Field)({ nullable: true, description: 'How to use it, as Markdown, in the language asked (English stands in). Only when one template is asked for.' }),
|
|
39
|
+
tslib_1.__metadata("design:type", String)
|
|
40
|
+
], FigureRecipeTemplate.prototype, "guide", void 0);
|
|
41
|
+
tslib_1.__decorate([
|
|
42
|
+
(0, type_graphql_1.Field)({ description: 'Whether it has a thumbnail image.' }),
|
|
43
|
+
tslib_1.__metadata("design:type", Boolean)
|
|
44
|
+
], FigureRecipeTemplate.prototype, "hasThumbnail", void 0);
|
|
45
|
+
exports.FigureRecipeTemplate = FigureRecipeTemplate = tslib_1.__decorate([
|
|
46
|
+
(0, type_graphql_1.ObjectType)({ description: 'A recipe template the product ships: parts, their fastenings and motion, put onto a part in one step (ADR-0095).' })
|
|
47
|
+
], FigureRecipeTemplate);
|
|
48
|
+
//# sourceMappingURL=figure-recipe-type.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"figure-recipe-type.js","sourceRoot":"","sources":["../../../server/service/figure-recipe/figure-recipe-type.ts"],"names":[],"mappings":";;;;AAAA,+CAAgD;AAGzC,IAAM,oBAAoB,GAA1B,MAAM,oBAAoB;CA2BhC,CAAA;AA3BY,oDAAoB;AAE/B;IADC,IAAA,oBAAK,EAAC,EAAE,WAAW,EAAE,oDAAoD,EAAE,CAAC;;kDACjE;AAGZ;IADC,IAAA,oBAAK,EAAC,EAAE,WAAW,EAAE,sDAAsD,EAAE,CAAC;;sDAC/D;AAGhB;IADC,IAAA,oBAAK,EAAC,IAAI,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,EAAE,WAAW,EAAE,uBAAuB,EAAE,CAAC;;kDACpD;AAGd;IADC,IAAA,oBAAK,EAAC,EAAE,WAAW,EAAE,gFAAgF,EAAE,CAAC;;oDAC3F;AAGd;IADC,IAAA,oBAAK,EAAC,EAAE,WAAW,EAAE,sDAAsD,EAAE,CAAC;;mDAClE;AAGb;IADC,IAAA,oBAAK,EAAC,EAAE,WAAW,EAAE,qEAAqE,EAAE,CAAC;;yDAC3E;AAGnB;IADC,IAAA,oBAAK,EAAC,EAAE,WAAW,EAAE,sEAAsE,EAAE,CAAC;;oDACjF;AAGd;IADC,IAAA,oBAAK,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,6GAA6G,EAAE,CAAC;;mDACxI;AAGd;IADC,IAAA,oBAAK,EAAC,EAAE,WAAW,EAAE,mCAAmC,EAAE,CAAC;;0DACvC;+BA1BV,oBAAoB;IADhC,IAAA,yBAAU,EAAC,EAAE,WAAW,EAAE,kHAAkH,EAAE,CAAC;GACnI,oBAAoB,CA2BhC","sourcesContent":["import { Field, ObjectType } from 'type-graphql'\n\n@ObjectType({ description: 'A recipe template the product ships: parts, their fastenings and motion, put onto a part in one step (ADR-0095).' })\nexport class FigureRecipeTemplate {\n @Field({ description: 'The template name: lower case, digits and hyphens.' })\n name: string\n\n @Field({ description: 'The category it is listed under (door, conveyor, …).' })\n category: string\n\n @Field(type => [String], { description: 'Words it is found by.' })\n tags: string[]\n\n @Field({ description: \"'part' when it is put onto a chosen part, 'figure' when onto the whole figure.\" })\n target: string\n\n @Field({ description: 'Its title in the language asked (English stands in).' })\n title: string\n\n @Field({ description: 'Its one-line description in the language asked (English stands in).' })\n description: string\n\n @Field({ description: 'The recipe JSON (figure-model V3Recipe), as the modeller applies it.' })\n source: string\n\n @Field({ nullable: true, description: 'How to use it, as Markdown, in the language asked (English stands in). Only when one template is asked for.' })\n guide?: string\n\n @Field({ description: 'Whether it has a thumbnail image.' })\n hasThumbnail: boolean\n}\n"]}
|
|
@@ -1,4 +1,2 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
export declare const entities: (typeof FigureRecipe)[];
|
|
4
|
-
export declare const resolvers: (typeof FigureRecipeResolver)[];
|
|
1
|
+
import { FigureRecipeTemplateQuery } from './figure-recipe-resolver.js';
|
|
2
|
+
export declare const resolvers: (typeof FigureRecipeTemplateQuery)[];
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.resolvers =
|
|
4
|
-
const figure_recipe_js_1 = require("./figure-recipe.js");
|
|
3
|
+
exports.resolvers = void 0;
|
|
5
4
|
const figure_recipe_resolver_js_1 = require("./figure-recipe-resolver.js");
|
|
6
|
-
exports.
|
|
7
|
-
exports.resolvers = [figure_recipe_resolver_js_1.FigureRecipeResolver];
|
|
5
|
+
exports.resolvers = [figure_recipe_resolver_js_1.FigureRecipeTemplateQuery];
|
|
8
6
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../server/service/figure-recipe/index.ts"],"names":[],"mappings":";;;AAAA,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../server/service/figure-recipe/index.ts"],"names":[],"mappings":";;;AAAA,2EAAuE;AAE1D,QAAA,SAAS,GAAG,CAAC,qDAAyB,CAAC,CAAA","sourcesContent":["import { FigureRecipeTemplateQuery } from './figure-recipe-resolver.js'\n\nexport const resolvers = [FigureRecipeTemplateQuery]\n"]}
|
|
@@ -2,10 +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 * from './figure-recipe/figure-recipe.js';
|
|
6
|
-
export {
|
|
7
|
-
export declare const entities: typeof import("./figure
|
|
5
|
+
export * from './figure-recipe/figure-recipe-type.js';
|
|
6
|
+
export { recipeTemplates, inLanguage, RECIPE_DIR } from './figure-recipe/figure-recipe-templates.js';
|
|
7
|
+
export declare const entities: (typeof import("./figure/figure.js").Figure | typeof import("./figure/figure-history.js").FigureHistory)[];
|
|
8
8
|
export declare const subscribers: typeof import("./figure/event-subscriber.js").FigureHistoryEntitySubscriber[];
|
|
9
9
|
export declare const schema: {
|
|
10
|
-
resolverClasses: (typeof import("./figure/figure-query.js").FigureQuery | typeof import("./figure/figure-mutation.js").FigureMutation | typeof import("./figure-recipe/figure-recipe-resolver.js").
|
|
10
|
+
resolverClasses: (typeof import("./figure/figure-query.js").FigureQuery | typeof import("./figure/figure-mutation.js").FigureMutation | typeof import("./figure-recipe/figure-recipe-resolver.js").FigureRecipeTemplateQuery)[];
|
|
11
11
|
};
|
|
@@ -1,22 +1,21 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.schema = exports.subscribers = exports.entities = exports.
|
|
3
|
+
exports.schema = exports.subscribers = exports.entities = exports.RECIPE_DIR = exports.inLanguage = exports.recipeTemplates = 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
|
|
12
|
-
Object.defineProperty(exports, "
|
|
13
|
-
Object.defineProperty(exports, "
|
|
14
|
-
Object.defineProperty(exports, "
|
|
15
|
-
Object.defineProperty(exports, "builtInRecipes", { enumerable: true, get: function () { return figure_recipe_store_js_1.builtInRecipes; } });
|
|
10
|
+
tslib_1.__exportStar(require("./figure-recipe/figure-recipe-type.js"), exports);
|
|
11
|
+
var figure_recipe_templates_js_1 = require("./figure-recipe/figure-recipe-templates.js");
|
|
12
|
+
Object.defineProperty(exports, "recipeTemplates", { enumerable: true, get: function () { return figure_recipe_templates_js_1.recipeTemplates; } });
|
|
13
|
+
Object.defineProperty(exports, "inLanguage", { enumerable: true, get: function () { return figure_recipe_templates_js_1.inLanguage; } });
|
|
14
|
+
Object.defineProperty(exports, "RECIPE_DIR", { enumerable: true, get: function () { return figure_recipe_templates_js_1.RECIPE_DIR; } });
|
|
16
15
|
// Entities, resolvers
|
|
17
16
|
const index_js_1 = require("./figure/index.js");
|
|
18
17
|
const index_js_2 = require("./figure-recipe/index.js");
|
|
19
|
-
exports.entities = [...index_js_1.entities
|
|
18
|
+
exports.entities = [...index_js_1.entities];
|
|
20
19
|
/* 판본 스냅샷을 뜨는 구독자. 셸이 이 이름으로 모아 TypeORM 에 등록한다(board-service 와 같다). */
|
|
21
20
|
exports.subscribers = [...index_js_1.subscribers];
|
|
22
21
|
/*
|
|
@@ -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;AAC1C,
|
|
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,gFAAqD;AACrD,yFAAoG;AAA3F,6HAAA,eAAe,OAAA;AAAE,wHAAA,UAAU,OAAA;AAAE,wHAAA,UAAU,OAAA;AAEhD,sBAAsB;AACtB,gDAI0B;AAC1B,uDAAuE;AAE1D,QAAA,QAAQ,GAAG,CAAC,GAAG,mBAAc,CAAC,CAAA;AAE3C,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-type.js'\nexport { recipeTemplates, inLanguage, RECIPE_DIR } from './figure-recipe/figure-recipe-templates.js'\n\n// Entities, resolvers\nimport {\n entities as FigureEntities,\n resolvers as FigureResolvers,\n subscribers as FigureSubscribers\n} from './figure/index.js'\nimport { resolvers as RecipeResolvers } from './figure-recipe/index.js'\n\nexport const entities = [...FigureEntities]\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"]}
|